【问题标题】:Schema based Multi tenancy in Loopback 4Loopback 4 中基于模式的多租户
【发布时间】:2020-06-26 01:10:10
【问题描述】:

用例

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

问题

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

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

注意事项:

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

【问题讨论】:

  • 好问题!我也有这个问题!如果有办法即时切换到模式就好了!
  • @EdwinIkechukwuOkonkwo 接受的答案效果很好。你可以试试看。谢谢

标签: loopbackjs loopback4


【解决方案1】:

您可以在运行时创建 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);

然后使用此存储库执行查找、创建和其他方法。 有一个示例实现 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);

【讨论】:

  • 请注意,示例应用将为每个传入请求创建一个新的数据源实例。这将反过来创建一个到 PostgreSQL 数据库的新连接池。因此,数据库连接不会跨请求重用。这可能会成为性能问题。
  • @MiroslavBajtoš 你在说并行请求吗?
  • 请求是否并行并不重要。 UserService 被定义为瞬态的,LB 为每个传入的请求创建一个新实例。把console.log(或console.trace)放到构造函数中自己看。
  • @MiroslavBajtoš 我已经对您告诉的问题进行了一些更改,并检查了数据库连接现在对我来说工作正常。请审查一次。 1. 我知道数据源设置是单例的,所以为此我们可以将这个数据源与其他数据源分开使用,这样应用程序就不会因为其他人而崩溃。 2. 我知道您正在为此构建功能,但我们迫切需要使用环回 2.0.0 来实现此功能。代码链接github.com/dev-hitesh-gupta/dynamic-schema-example
  • @MiroslavBajtoš 请您看看 Hitesh 的新修改。他的代码工作正常吗(不会为每个传入的请求创建一个新的数据库实例)?
【解决方案2】:

来自 LoopBack 团队的问候 ?

LoopBack 4 尚未提供一流的多租户支持。我打开了一个 GitHub 问题来讨论不同的可能解决方案,请参阅 loopback-next#5056。

一种选择是调整特定于模型的存储库类以根据当前用户设置架构。这需要在@loopback/repository 中实现一个小的增强功能,因此该解决方案目前无法开箱即用。我将在下面交叉发布我评论的相关部分,请参阅 GitHub 问题以获取完整上下文。

使用架构的轻量级租户隔离

在此设置中,身份验证层和所有租户共享相同的数据库名称并使用相同的凭据(数据库用户)访问数据。我们在数据库中定义了 1+N 个模式:第一个模式由身份验证层使用,另外我们为每个租户都有一个模式。所有数据库查询将使用相同的 LB 数据源,因此共享相同的连接池。

在实现方面,我们需要调整 LB4 模型向数据源注册的方式。我们希望创建特定于租户的杂耍模型,而不是为所有用户创建相同的后备杂耍模型。

从概念上讲,这可以通过调整 Repository 构造函数来实现。

export class ProductRepository extends DefaultCrudRepository<
  Product,
  typeof Product.prototype.id
> {
  constructor(
    @inject('datasources.db') dataSource: juggler.DataSource,
    @inject(SecurityBindings.USER) currentUser: UserProfile,
  ) {
    super(
      // model constructor
      Product, 
      // datasource to use
      dataSource, 
      // new feature to be implemented in @loopback/repository:
      // allow repository users to overwrite model settings
      {schema: currentUser.name},
    );
  }
}

【讨论】:

  • 如果我们同时获得模型运行时(对于特定架构),那么我们是否能够在同一架构中获得相同运行时的 repo?
  • 我恐怕不明白你说的在运行时获取模型是什么意思?
  • @MiroslavBajtoš 这个问题有进展吗?我浏览了Ramond's example 的PR,但是没看到最终的结果。您是否最终决定在 LB 上启用多租户?
  • @mbnoimi 恐怕多租户并不是我们的优先事项。我认为 Raymond 的示例应该为构建您自己的多租户应用程序提供一个很好的起点。 AFAIK,我们没有任何更新或更好的东西。
  • @MiroslavBajtoš 听到这个消息我很难过。不幸的是,我在 LB 中遇到了很多问题!您是否有任何路线图或里程碑要遵循(Github 中的milestones 已过时)只是为了了解正在发生的事情。
猜你喜欢
  • 2020-02-02
  • 2018-02-20
  • 2013-03-30
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
相关资源
最近更新 更多