1

I have a scheduled task using SpringBoot Scheduled to run Monday through Friday at 10 AM. I'm running my application in a docker container and my machine is suspended from 6pm to 9am overnight. When I start my machine, my tasks that were scheduled for 10 hours do not run unless I restart the container before the scheduled time. I have application logs, no log record occurs that is inside the method with the @Scheduled annotation when this occurs. With that I believe it's a deadlock. I wonder if there is any way to detect a deadlock in the Springboot Scheduled programmatically.

My Cron expression: "0 0 10 * * MON-FRI"

Note: I'm testing on my machine to later host on an appropriate server.

  • See https://stackoverflow.com/questions/39917757/stop-spring-scheduled-execution-if-it-hangs-after-some-fixed-time – Ori Marko Jul 22 '19 at 14:00
  • @user7294900 In the case of this link that indicated to me the goal is to stop a scheduled task. I wonder if it is possible to detect that a scheduled task has been deadlocked. – Gladson Bruno Jul 22 '19 at 14:13

1 Answers1

0

AFAIK there is no standard way in Java to detect if the system went in standby/hibernate. Scheduling in Spring is based on the timing facilites in Java, facilites which are not intended to work across OS sleep or hibernate conditions. In short, if the JVM cannot detect when system goes in standby neither can Spring.

As I see it you have the following options:

  • notify the application when the system is resumed then re-schedule the tasks. This is a possible solution built around pm utils on Ubuntu. This one is for Windows.
  • add an additional task that runs, say every 10 seconds and reads the system time. If there is an appreciable difference between two time readings it means your system went to sleep and then resumed.

The following for example restarts the context if a time gap (delta) greater than 1s is detected:

@SpringBootApplication
@EnableScheduling
public class Application {

  private static ConfigurableApplicationContext context;

  public static void main(String[] args) {
    context = SpringApplication.run(Application.class, args);
  }

  static LocalTime lastDetectedTime;
  static long delta = 1000;
  static final long CHECK_INTERVAL = 5000;

  @Scheduled(fixedDelay = CHECK_INTERVAL, initialDelay = CHECK_INTERVAL)
  public static void restartIfTimeMismatch() {

    if(lastDetectedTime == null) {
      lastDetectedTime = LocalTime.now();
    }
    LocalTime currentTime = LocalTime.now();
    long diff = Duration.between(lastDetectedTime, currentTime).toMillis();
    lastDetectedTime = currentTime;

    if(diff > CHECK_INTERVAL + delta) {
      Thread thread = new Thread(() -> {
        context.close();
        context = SpringApplication.run(Application.class);
      });

      lastDetectedTime = null;
      thread.setDaemon(false);
      thread.start();

    }
  }
}

Hope it helps.

b0gusb
  • 4,283
  • 2
  • 14
  • 33