简体   繁体   中英

spring boot java scheduler should be executed only once for three dyno's per day

i have spring boot and java application. at particular time of the day it should execute a method. so in the production server we have kept 4 dyno's and because of 4 dyno's it is executing 4 times per day. so i have used cache and getting the date . based on the date i try to execute the method only once .still it is executing 4 times.

  @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();
      }
    }
  }

the above code is written in a config java class.

  1. the schedulerService.processScheduled(); should be triggered only once a day irrespective of no of the dyno's. can anyone help me on this ?

I am assuming you are using Heroku Dynos, so there are 4 separate instances of your app running in production. Since there are 4 separate instances, your use of synchronized will be of little use here. All 4 of your instances are getting invoked at the same time, so there is a chance that, all of them will get the value of redisTemplate.getValue("DATE") as not null. You need an atomic operation with an centralized entity. Redis does serve as an centralized entity, but redisTemplate.getValue("DATE") and then redisTemplate.putValue("DATE", LocalDate.now()) is not an atomic operation. So it is very possible that 4 instances call redisTemplate.getValue("DATE") and get the real date. Since all 4 of them are not null, they will all update the value and then process your operation.

You should try using redisTemplate.delete(key) . It is an atomic operation which returns true if the key is deleted else returns false. So your code may look like this.

@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());

      }
    
  }

Or you can update the Date value after some time of the invocation with @Scheduled

@Scheduled(zone = "${scheduler.zone}", cron = "${scheduler.flag.update.job}")
public  void updateDateFlag() {
    redisTemplate.putValue("DATE", LocalDate.now());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM