【问题标题】:Running Only Once A Schedule Job Across Multiple Instances跨多个实例的计划作业仅运行一次
【发布时间】:2020-07-20 11:44:10
【问题描述】:

我有一个schedule job,每个月底都会运行。运行后会将一些数据保存到数据库中。

当我扩展应用程序(例如使用 2 个实例)时,两个实例都运行计划作业并保存数据,并且在一天结束时我的数据库具有相同的数据。

所以我希望调度作业只运行一次,而不管云端的实例数量如何。

【问题讨论】:

  • 如果您在 CloudFoundry 上运行,为什么不使用调度程序?
  • 我是 CloudFoundry 的新手,我不知道 Cloud Foundry 可以处理这样的事情
  • 您是在本地还是在公共云中运行 CloudFoundry?
  • 这是一个私有云。
  • 所以请询问您的 Cloud Foundry 管理员如何使用调度程序

标签: java spring spring-boot cloud-foundry


【解决方案1】:

在我的项目中,我维护了一个数据库表来为每个需要在集群中执行一次的作业持有一个锁。 当一个 Job 被触发时,它首先尝试从数据库获取锁,如果它只获得那个锁,那么它将被执行。如果获取锁失败,则作业将不会被执行。

你也可以看看Quartz job的聚类特性。

http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/introduction.html

【讨论】:

    【解决方案2】:

    我同意 cmets。如果您可以使用调度程序,那将是您最好、最灵活的选择。此外,调度程序应该将您的作业作为 Cloud Foundry 上的“任务”执行。该任务只会在一个实例上运行,因此您无需担心您的应用程序正在使用多少个实例(在这方面两者是分开的)。

    如果您使用的是 Pivotal Cloud Foundry/Tanzu Cloud Foundry,您可以要求您的运营团队安装一个调度程序。我不知道 CF 的其他变体,但我认为还有其他调度程序。

    https://network.pivotal.io/products/p-scheduler/


    如果不能选择使用调度程序,那么这是您需要在应用程序中处理的问题。使用共享锁的方案是不错的,不过还有一个小技巧可以在Cloud Foundry上做,我觉得稍微简单一点。

    当您的应用程序运行时,平台会设置某些环境变量。有一个叫做INSTANCE_INDEX,它有一个数字,表示应用程序正在运行的实例。它是从零开始的,因此您的第一个应用实例将在实例零上运行,第二个实例将在一个实例上运行,等等。

    在您的代码中,只需查看实例索引并查看它是否为零。如果索引不为零,则让您的任务结束而不做任何事情。如果它为零,那么让任务继续并完成它的工作。该任务将在每个应用程序实例上执行,但它只会在第一个实例上工作。这是一种保证数据库迁移或后台作业只运行一次的简单方法。


    最后一个选择是使用多个进程。这是 Cloud Foundry 的一项功能,可让您运行不同的进程,例如您的 Web 进程和后台工作进程。

    https://docs.cloudfoundry.org/devguide/multiple-processes.html

    此功能的有趣之处在于,您可以相互独立地扩展不同的流程。因此,您可以运行尽可能多的 Web 进程,但只有一个后台工作人员可以保证您的后台进程只运行一次。

    也就是说,这种方法的缺点是您最终会为每个进程使用单独的容器,并且后台进程需要继续运行。基金会希望它是一个长期运行的过程,而不是一个有限持续时间的批处理作业。您可以通过将您的周期性任务包装成一个循环或使进程永远运行的东西来解决这个问题。

    我不会真的推荐这个选项,但我想把它扔掉以防万一。

    【讨论】:

      【解决方案3】:

      你可以在你的方法中使用@SnapLock注解来保证任务只运行一次。请参阅此 repo 中的文档https://github.com/luismpcosta/snap-scheduler

      示例: 导入maven依赖

      <dependency>
        <groupId>io.opensw.scheduler</groupId>
        <artifactId>snap-scheduler-core</artifactId>
        <version>0.3.0</version>
      </dependency>
      

      导入maven依赖后,需要创建所需的表tables。

      最后,看看下面如何注释方法,保证只运行一次 @SnapLock 注释:

      import io.opensw.scheduler.core.annotations.SnapLock;
      ...
      
        @SnapLock(key = "UNIQUE_TASK_KEY", time = 60)
        @Scheduled(fixedRate = 30000)
        public void reportCurrentTime() {
          ...
        }
      

      通过这种方法,您还可以保证对任务执行的审计。

      【讨论】:

        猜你喜欢
        • 2016-04-24
        • 1970-01-01
        • 1970-01-01
        • 2020-06-25
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-12
        相关资源
        最近更新 更多