【问题标题】:Prevent multiple cron running in nest.js on docker防止在docker上的nest.js中运行多个cron
【发布时间】:2022-01-07 02:36:33
【问题描述】:

在 docker 中,我们为我们的微服务使用了 deploy: replicas: 3。我们有一些 Cronjob,问题是运行所有 cronjob 的系统被调用了 3 次,这不是我们想要的。我们只想运行一次。 nest.js 中的 cron 示例:

  @Cron(CronExpression.EVERY_5_MINUTES)
  async runBiEventProcessor() {
    const calculationDate = new Date()
    Logger.log(`Bi Event Processor started at ${calculationDate}`)

如何在不将副本更改为 1 的情况下只运行此 cron 一次?

【问题讨论】:

    标签: docker concurrency cron nestjs


    【解决方案1】:

    当 cron 或后台作业是同时运行多个实例的应用程序的一部分时,这是一个相当普遍的问题。

    有多种方法可以处理这种情况。如果您没有具体的解决方案,以下是一些解决方法:

    1. 仅为后台处理创建单独的服务,并确保一次只运行一个实例。

    2. 将 cron 作业公开为 API,并触发 API 启动后台处理。在这种情况下,负载均衡器只会将请求交给一个实例。这种方法将确保只有一个实例来处理这项工作。您仍然需要一个外部实体来访问 API,它可以是内部的或第三方的。

    3. 使用 Bull Queue 中的可重复作业功能或提供类似功能的任何其他工具或库。 Bull 将把工作交给任何活跃的处理器。这样,它确保作业仅由一个活动处理器处理一次。 Nest.js 具有相同的 wrapper。详细了解 Bull 队列可重复作业 here

    4. 实现自定义锁定机制 听起来并不难。其他框架中的许多其他调度程序都使用类似的原则来处理并发。

      • 如果您使用的是 RDBMS,请使用事务和锁定。在数据库中创建 cron 记录。第一个 cron 进入并处理后立即获取锁。其他并发作业将失败或超时,因为它们将无法获取锁。但是您需要在这种方法中处理一些情况,以使其没有错误且完美无缺。
      • 如果您使用的是 MongoDB 或任何支持 TTL(生存时间)设置和唯一索引的类似数据库。将文档插入数据库中,其中文档中的一个字段具有唯一约束,以确保另一个作业将无法再插入一个文档,因为它将由于数据库级别的唯一约束而失败。另外,确保文档上的 TTL(生存时间索引);这样文档将在配置的时间后被删除。

    如果您没有任何其他具体选项,这些是解决方法。

    【讨论】:

    • 如果您有任何进一步的疑问或者您不了解特定部分。让我知道;我将编辑答案以使其更清楚。
    【解决方案2】:

    这里有很多关于如何解决这个问题的选项,但我建议创建一个 NestJS 微服务(或普通 nodeJS)来仅运行 cronjob 并将其存储在共享数据库中,例如将结果存储在 Redis 中.

    您运行 cronjob 的微服务不会公开任何内容,它只会启动您的 cronjob:

    const app = await NestFactory.create(
      WorkerModule,
    );
    await app.init();
    

    您的WorkerModule 导入调度程序并在那里配置调度程序。您可以将 cronjob 的结果写入 Redis 等共享数据库。

    现在您仍然可以使用 3 个副本,但阻止在所有副本中注册 cron 作业。

    【讨论】:

    • 我不想为此创建微服务。需要另一种方法。
    • 然后以同样的方法,使用一些共享数据库并将 cronjob 的结果与时间戳一起存储。如果存在,请跳过运行。
    猜你喜欢
    • 2017-10-30
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 2019-05-17
    • 2019-10-13
    • 1970-01-01
    • 2015-04-22
    • 2021-03-04
    相关资源
    最近更新 更多