防止在 docker 上的 Nest.js 中运行多个 cron

Axo*_*xon 6 concurrency cron docker nestjs

在 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}`)
Run Code Online (Sandbox Code Playgroud)

我怎样才能只运行一次这个 cron 而不将副本更改为 1?

Amo*_*ble 20

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

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

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

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

  3. 使用 Bull Queue 中的可重复作业功能或提供类似功能的任何其他工具或库。Bull 会将工作移交给任何活跃的处理者。这样,它可以确保作业仅由一个活动处理器处理一次。Nest.js 有相同的包装器。在此处阅读有关 Bull 队列可重复作业的更多信息。

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

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

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