Loopback 4 中基于模式的多租户

use*_*450 5 loopbackjs loopback4

用例

在基于模式的多租户应用程序中,通常有一个具有多个模式的数据库。一种模式是存储通用应用程序数据的主要模式,一种用于应用程序的每个租户。每次有新客户注册到系统时,都会在数据库中自动创建一个新的隔离模式。这意味着,模式是在运行时创建的,并且事先不知道。客户的模式是根据客户的域命名的。当请求进入系统时,用户将得到验证并使用主模式上的数据选择模式。然后大多数/所有后续数据库操作都转到租户特定的模式。如您所见,我们要使用的模式仅在运行时才知道。

问题

如何在运行时选择模式?我们正在使用 postgres 连接器。我们应该能够在运行时切换模式。

另一个问题是如何为不同的租户运行迁移?

笔记:

db-schema 需要以请求范围的方式设置,以避免为可能属于其他客户的其他请求设置架构。为整个连接设置架构不是一个选项。

Hit*_*pta 0

您可以在运行时创建 DefaultCrudRepository (使用遗留杂耍模型和数据源的 CRUD 存储库的默认实现),它需要两个参数

  1. 数据源
  2. 模型

现在使用所需的设置实例化数据源,包括您要使用的架构然后将您的模型和数据源提供给 DefaultCrudRepository 实例,如下所示:-

const ds = new PostgresDataSource({
  connector: 'postgresql',
  host: 'some host',
  port: 'some port',
  user: 'some user',
  password: 'password',
  database: 'database',
  schema: 'schema for that particular tenant',
});
const repo =  new DefaultCrudRepository(SomeModel, ds);
Run Code Online (Sandbox Code Playgroud)

然后使用这个存储库来执行查找、创建等方法。有一个示例实现 https://github.com/hitesh2067/dynamic-schema-example

我已将架构作为查询参数传递,但您可以使用任何其他方式来提供架构

更新的解决方案:-

现在 Loopback 已经为应用程序上下文和请求上下文提供了中间件和更好的上下文分离。我们可以使用它动态连接到任何数据源(希望连接器安装在 package.json 中)并将其绑定到应用程序上下文,然后将该绑定临时绑定到 UserRepository (或任何多租户存储库)指向的数据源在请求上下文中。

示例写在 https://github.com/dev-hitesh-gupta/loopback4-multi-tenant-multi-datasource-example

实施会像

const tenant = await this.getTenant(requestCtx);
if (tenant == null) return;
const tenantData = await this.tenantRepo.findById(tenant.id);
requestCtx.bind(CURRENT_TENANT).to(tenantData);
const tenantDbName = `datasources.multi-tenant-db.${tenantData.id}`;
// adding datasource if not present
if (!this.application.isBound(tenantDbName)) {
  const tenantDb = new juggler.DataSource({
    name: tenantDbName,
    ...tenantData.dbConfig,
  });
  this.application.bind(tenantDbName).to(tenantDb).tag('datasource');
}
// Pointing to a default datasource in request context
requestCtx
  .bind('datasources.multi-tenant-db')
  .toAlias(tenantDbName);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,示例应用程序将为每个传入请求创建一个新的数据源实例。这将依次创建一个新的 PostgreSQL 数据库连接池。因此,数据库连接不会在请求之间重用。这可能会成为性能问题。 (2认同)