我们有一个Spring Boot应用程序,并且已安排任务。
我们希望在多个服务器上部署我们的应用程序,因此将是多个应用程序实例。
如何将Spring配置为仅在指定的服务器上运行计划任务?
答案 0 :(得分:6)
这是一个非常广泛的话题。实现这一目标有很多选择。
您可以将应用程序配置为具有多个配置文件。例如,使用另一个个人资料' cron' 。并使用此配置文件仅在一台服务器上启动您的应用程序因此,例如,在生产环境中,您有三台服务器(S1,S2,S3),那么您可以在S1上运行配置文件prod和cron(-Dspring.profiles.active=prod,cron
)。在S2和S3上只需使用prod配置文件(-Dspring.profiles.active=prod
)。
在代码中,您可以在调度程序类上使用@Profile("cron")
。这样,只有当cron配置文件处于活动状态时才会执行
使用分布式锁。如果您的环境中有Zookeeper,则可以使用它来实现分布式锁定系统。
您可以使用某个数据库(mysql)并创建示例代码以锁定其中一个表并添加一个条目。无论哪个实例获得锁定,都会在此数据库中创建一个条目并执行cron作业。你需要
检查代码,如果getLock()
成功,则继续执行。 Mysql有像LOCK TABLES
这样的实用程序,你可以使用它来逃避并发读/写。
答案 1 :(得分:6)
ShedLock 项目是专门为实现此目的而创建的。
依赖性-
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
配置-
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
实施-
@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "AnyUniqueName",
lockAtLeastForString = "PT5M", lockAtMostForString = "PT10M")
public void scheduledTask() {
// ...
}
这将确保仅一个实例应运行计划的任务。
如果只希望特定实例运行Scheduler任务,
您需要配置调度程序以使用属性文件并像这样控制调度程序开关-
@ConditionalOnProperty(
value = "scheduling.enabled", havingValue = "true", matchIfMissing = true
)
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulingConfig {
现在,您只需要为要运行Schedular的实例提供属性scheduling.enabled = true
。
答案 2 :(得分:2)
使用Spring执行此操作的最简单方法是使用环境变量和值注释:
1 - 在类中使用Value注释获取环境变量:
@Value("${TASK_ENABLED}")
private boolean taskEnabled;
2 - 检查taskEnabled值以执行任务:
@Scheduled(fixedDelay = 50000)
public void myTask() {
if (this.taskEnabled) {
//do stuff here...
}
}
3 - 为每台服务器设置正确的环境变量:
假:
java -DTASK_ENABLED=0 -jar software.jar
或
真:
java -DTASK_ENABLED=1 -jar software.jar
全局配置类示例
要使用全局配置类,您应该说它是一个带有@Component的组件,并注释一个set方法将值传递给静态字段。
1 - 使用静态字段创建配置类:
@Component
public class AppConfiguration {
public static boolean taskEnabled;
@Value("${TASK_ENABLED}")
public void setTaskEnabled(boolean taskEnabled) {
this.taskEnabled = taskEnabled;
}
}
2 - 检查taskEnabled值以执行任务:
@Scheduled(fixedDelay = 50000)
public void myTask() {
if (AppConfiguration.taskEnabled) {
//do stuff here...
}
}
3 - 为每台服务器设置正确的环境变量:
假:
java -DTASK_ENABLED=0 -jar software.jar
或
真:
java -DTASK_ENABLED=1 -jar software.jar
答案 3 :(得分:0)
我认为您需要的帮助来自另一篇文章的一个答案。
答案 4 :(得分:0)
最简单的解决方案是您可以为不同的实例使用不同的属性文件。步骤如下
@ConditionalOnProperty(prefix = "enable-scheduler", havingValue = "true")
注释您的调度程序类enable-scheduler=true
中添加一个布尔值enable-scheduler=true
,对于任何其他实例使用 enable-scheduler=false
在您的属性文件中。示例:
@Component
@ConditionalOnProperty(prefix = "enable-scheduler", havingValue = "true")
public class AnyScheduler {
private final Logger log = LoggerFactory.getLogger(getClass());
private final AnyService service;
@Autowired
public AnyScheduler(AnyService service) {
this.service = service;
}
@Scheduled(cron = "${scheduler-cron}")
public void syncModifiedCve() {
log.info("Scheduler started. . .");
service.doTask();
}
}