Sequelize с асинхронной конфигурацией в nodejs - PullRequest
0 голосов
/ 31 марта 2020

Я несколько дней ломал голову, так как не могу найти действительный пример конфигурации asyn c в Sequelize

Так что, как вы знаете, вы можете просто настроить экземпляр Sequelize следующим образом

const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname')

и затем объявите свою модель

const User = sequelize.define('User', {
  // Model attributes are defined here
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  lastName: {
    type: DataTypes.STRING
    // allowNull defaults to true
  }
}, {
  // Other model options go here
});

Однако что происходит, когда учетные данные db поступают из внешней службы?

const credentials = await getDbCredentials();
const sequelize = new Sequelize({credentials})


, поскольку создание последовательных моделей в сочетании с созданием экземпляра (в отличие от многих других ORM) становится большой проблемой.

Мое текущее решение заключается в следующем:


const Sequelize = require("sequelize");

// Models
const { User } = require("./User");

const env = process.env.NODE_ENV || "development";
const db = {};

let sequelize = null;

const initSequelize = async () => {
  if (!sequelize) {
      let configWithCredentials = {};

      if (env === "production") {
        const credentials = await getDbCredentials();
        const { password, username, dbname, engine, host, port } = credentials;
        configWithCredentials = {
          username,
          password,
          database: dbname,
          host,
          port,
          dialect: engine,
          operatorsAliases: 0
        };
      }

      const config = {
        development: {
          // Dev config 
        },
        production: configWithCredentials,
      };

      sequelize = new Sequelize(config[env]);

      sequelize.authenticate().then(() => {
         console.log("db authenticated")
        });
      });
  }

  db.User = User;

  db.sequelize = sequelize;
  db.Sequelize = Sequelize;
};

initSequelize().then(() => {
  console.log("done");
});

module.exports = db;

Однако я чувствую, что это не очень хороший подход из-за асинхронного характера инициализации, и иногда db не определен. Есть ли лучший способ приблизиться к этой вещи? Спасибо

Ответы [ 3 ]

1 голос
/ 31 марта 2020

Я думаю, что ваша база данных иногда не определена, потому что в вашей функции asyn c вы не «ждете» разрешения sequelize.authenticate (). Измените это:

sequelize.authenticate().then(() => {
         console.log("db authenticated")
        });

На это:

 await sequelize.authenticate()

 console.log("db authenticated")

То, что происходило, заключается в том, что ваша функция initSequelize asyn c будет разрешена до того, как будет выполнено обещание sequelize.authenticate. Это распространенная ошибка в JS. Я думаю, что эта настройка решит вашу проблему. Что касается «наилучшего подхода», я не вижу много, что можно сделать здесь, но, конечно, у меня нет полной картины.

0 голосов
/ 13 апреля 2020

Как это сильно изменило бы мой код. В итоге я создал сценарий в golang, который получает мои учетные данные «асинхронно» перед запуском моего сервера. Я использовал некоторый код из этого пакета: https://github.com/telia-oss/aws-env

И затем передал мой стартовый скрипт в качестве аргумента команды, чтобы я мог «наследовать» переменные среды ./getEnv exec -- node index.js

0 голосов
/ 31 марта 2020

Определение модели sequelize на самом деле является простым объектом, поэтому его можно установить заранее. Инициализация модели требует передачи экземпляра sequelize.

Настройка была немного более понятной для меня при использовании определений классов ES6 для моделей. sequelize.define заменяется вызовом Model.init, и все это можно сделать с помощью функции настройки asyn c.

const Sequelize = require('sequelize')
const { Model } = Sequelize

class User extends Model {
  static get modelFields(){
    return {
      id: {
        type: Sequelize.UUID,
        primaryKey: true,
        defaultValue: Sequelize.UUIDV4,
      },
      name: {
        type: Sequelize.STRING,
        allowNull: false,
        unique: true,
      }
    }
  }
  static get modelOptions(){
    return {
      version: true,
    }
  }
  static init(sequelize){
    const options = { ...this.modelOptions, sequelize }
    return super.init(this.modelFields, options)
  }
  static associate(models) {
    this.hasMany(models.Task)
  }
}

module.exports = User
const User = require('./User')

class Database {
   async static setup(){
     const credentials = await getCredentials()
     this.sequelize = new Sequelize(credentials)
     User.init(this.sequelize)
     this.User = User
     // When you have multiple models to associate add:
     this.User.associate(this)
   }
}

module.exports = Database

Из-за требования к учетным данным asyn c остальная часть вашего приложения должна будет справиться с задержкой, пока БД не будет настроена. Если это, например, приложение koa / express, вы можете отложить сервер .listen() до разрешения обещания Database.setup().

...