java - 在部署到 Azure 的 Spring Boot 应用程序中运行计划任务一次

标签 java spring spring-boot azure scheduled-tasks

在我的 Spring Boot 应用程序中,我有一个每分钟运行的计划任务。它运行一些查询来查找任何到期的通知,然后通过电子邮件发送它们

@Service
public class EmailSender {

    @Scheduled(cron = "0 * * * * *")
    public void runTask() {
      // send some emails
    }
}

当我在本地测试它时,它工作正常,但是当我将它部署到 Azure 时,每封电子邮件都会发送 2 个副本。这是因为在 Azure 中,我们运行(至少)2 个容器,这两个容器都启用了调度。

我寻找了每个容器的环境变量,调度程序会检查该环境变量,并且仅在该变量设置为“true”时才运行作业,但找不到任何可靠的方法来实现此目的。

我现在正在考虑以下内容

  • 删除@Scheduled 注释
  • 添加公开任务功能的 HTTP 端点( Controller 方法)
  • 使用 Azure Logic Apps 安排每分钟调用此端点(我还考虑过使用 WebJobs ,但 Linux 上的应用服务尚不支持此功能)。

这似乎增加了很多额外的复杂性,我想知道是否有更简单的解决方案?

最佳答案

默认情况下,Spring 无法处理多个实例上的调度程序同步 - 它会在每个节点上同时执行作业。所以有两种可能的解决方案:

使用外部库

您可以使用Spring ShedLock来处理这个问题。这里有一个您可以使用的指南:Spring ShedLock 。您可以在那里找到实现此锁所需的所有代码。

它通过使用数据库中的参数来工作,该参数向其他节点提供有关该任务的执行状态的信息。通过这种方式,ShedLock 可以防止您的计划任务同时执行多次。如果一个任务正在一个节点上执行,它会获取一个锁,以防止从另一个节点执行相同的任务。

您可以在他们的 Github Page 中找到更多信息关于如何使用不同的数据库处理它。

在不同实例中部署 Activity 调度程序

您可以创建两个不同的配置文件,例如,一个是 prod,另一个是 cron。然后,您可以将注释 @Profile("cron") 放在调度程序类上,以便它们仅在第二个配置文件上运行。

然后您必须构建应用程序两次:

  1. 第一次你必须用 -Dspring.profiles.active=prod 并且您可以正常部署它。
  2. 第二次构建它时 -Dspring.profiles.active=prod,cron,并且您必须将其部署在 不自动缩放的环境,以便您可以确定 这只是其中一个例子。

关于java - 在部署到 Azure 的 Spring Boot 应用程序中运行计划任务一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68468348/

相关文章:

java - 通过 docker-compose 将 JAVA_OPTS 传递给 spring boot 应用程序

java - 什么是使用空抽象类的好选择?

java - Android - 在本地配置文件中存储一些设置

java - 如何抛出除以 0 的异常?

java - 如何使用 Spring 创建不同类型对象的列表,但它们不是 bean

java - 设计适用于所有租户的 camunda 通用流程

java - Spring/Hibernate 连接泄漏与 ScrollableResults

java - 如何在java中将一个通用列表转换为另一个

java - 使用 spring mvc 在单击按钮时在表上添加行并将添加的行绑定(bind)到 modelAttribute

java - Spring 启动: how to add spring-data repositories in tests