[英]Run scheduled task once within Spring Boot app deployed to Azure
在我的 Spring Boot 应用程序中,我有一个每分钟运行一次的计划任务。 它运行一些查询来查找任何到期的通知,然后通过电子邮件发送它们
@Service
public class EmailSender {
@Scheduled(cron = "0 * * * * *")
public void runTask() {
// send some emails
}
}
当我在本地测试它时它工作正常,但是当我将它部署到 Azure 时,每封电子邮件都会发送 2 个副本。 这是因为在 Azure 中我们运行(至少)2 个容器,它们都启用了调度。
我寻找了一个每个容器的环境变量,调度程序会检查它,并且只有在此变量设置为“true”时才运行作业,但找不到任何可靠的方法来实现这一点。
我现在正在考虑以下内容
这似乎增加了很多额外的复杂性,我想知道是否有更简单的解决方案?
默认情况下,Spring 无法处理多个实例上的调度程序同步——而是在每个节点上同时执行作业。 所以有两种可能的解决方案:
不过,您可以使用Spring ShedLock来处理此问题。 这里有一个您可以使用的指南: Spring ShedLock 。 您可以在那里找到实现此锁所需的所有代码。
它通过使用数据库中的参数来工作,该参数将有关该任务执行状态的信息提供给其他节点。 通过这种方式 ShedLock 可以防止您的计划任务同时执行多次。 如果一个任务正在一个节点上执行,它会获取一个锁,以防止从另一个节点执行相同的任务。
您可以在他们的Github 页面中找到有关如何使用不同数据库处理它的更多信息。
您可以创建两个不同的配置文件,例如,一个是prod
,另一个是cron
。 然后,您可以将注释@Profile("cron")
放在调度程序类上,以便它们仅在第二个配置文件上运行。
然后你必须构建应用程序两次:
-Dspring.profiles.active=prod
构建它并正常部署它。-Dspring.profiles.active=prod,cron
构建它时,您必须将其部署在非自动缩放的环境中,以便确保只有一个实例。(选项 3 是@MDeinum 评论中的选项)
分解您的代码,以便可执行作业针对 REST 请求运行,并受到适当身份验证的保护(GUID 参数足以满足此目的,请随意使用更强大的方案)。 禁用@Scheduled
注释提供的调度。 使用 Azure 自动化帐户定期调用 REST API。
这个想法是 REST 调用被路由到一个节点,所以只有一个节点被唤醒。
缺点是安全性,因为您必须公开一个仅运行作业的 API,即。 可以重复运行,并且可能被滥用。 即使它不暴露于互联网,有人可能会反复curl
使用有效的开发者令牌是API。
我对这种方法很满意,因为在某些时候我将需要实现一个“强制运行计划任务”功能,以便在先前的作业执行失败时使用。
就我个人而言,我必须对我参与的每个项目都提出这种要求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.