spring boot java scheduler应该只为三个dyno执行一次';每天多少钱
我有spring boot和java应用程序。在一天中的特定时间,它应该执行一个方法。因此,在生产服务器中,我们保留了4个dyno,由于4个dyno,它每天执行4次。所以我使用了缓存来获取日期。根据日期,我只尝试执行一次该方法,但仍执行了4次spring boot java scheduler应该只为三个dyno执行一次';每天多少钱,java,spring,multithreading,spring-boot,concurrency,Java,Spring,Multithreading,Spring Boot,Concurrency,我有spring boot和java应用程序。在一天中的特定时间,它应该执行一个方法。因此,在生产服务器中,我们保留了4个dyno,由于4个dyno,它每天执行4次。所以我使用了缓存来获取日期。根据日期,我只尝试执行一次该方法,但仍执行了4次 @Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.cron.job}") public void processScheduled() {
@Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.cron.job}")
public void processScheduled() {
synchronized(this) {
LocalDate localDate = redisTemplate.getValue("DATE");
if (localDate == null || LocalDate.now().isAfter(localDate)) {
log.info("Entered process in SchedulerConfig");
redisTemplate.putValue("DATE", LocalDate.now());
schedulerService.processScheduled();
}
}
}
上面的代码是在ConfigJava类中编写的
我假设您使用的是Heroku Dynos,因此您的应用程序有4个独立的实例在生产环境中运行。由于有4个单独的实例,因此您使用的
synchronized
在这里没有什么用处。您的所有4个实例都将同时被调用,因此有可能所有实例都将redisTemplate.getValue(“DATE”)
的值设置为非空。您需要一个具有集中实体的原子操作。Redis确实是一个集中的实体,但是redisTemplate.getValue(“DATE”)
和redisTemplate.putValue(“DATE”,LocalDate.now())
不是一个原子操作。因此,很可能有4个实例调用redisTemplate.getValue(“日期”)
并获取实际日期。因为所有4个都不是null,所以它们都将更新值,然后处理您的操作
您应该尝试使用redisTemplate.delete(key)
。这是一个原子操作,如果删除密钥,则返回true,否则返回false。因此,您的代码可能如下所示
@Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.cron.job}")
public void processScheduled() {
boolean isDeleted= redisTemplate.delete("DATE"); // only one will get true, other will get false.
if (isDeleted) {
log.info("Entered process in SchedulerConfig");
schedulerService.processScheduled();
// sleep for some time and then update the date value
redisTemplate.putValue("DATE", LocalDate.now());
}
}
或者,可以在调用一段时间后使用@Scheduled更新日期值
@Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.flag.update.job}")
public void updateDateFlag() {
redisTemplate.putValue("DATE", LocalDate.now());
}
当请求同时出现时,这可以正常工作。有些时候,dyno的间隔是秒,这一次它是第二次执行调度程序。是的,我还注意到,redistemplate.putValue in if是罪魁祸首。您需要在调用时间跨度之后填充日期标志。在设置日期值之前,您可以使用另一个@Scheduled或sleep一段时间。