background

Quartz is a rich, open source, distributed task invocation framework that has been used in many of my projects to implement scheduling capabilities. A common requirement for scheduled tasks is that Web applications control the start, stop, and scheduling period of scheduled tasks.

This paper discusses whether it will take effect immediately if the pauseJob, deleteJob and rescheduleJob methods of Scheduler class are used to rescheduleJob for the currently scheduled and time-consuming task.

In this case, does the execute method of the current Job class terminate immediately or does the new task scheduling take effect only after the current Job completes?

Task scheduling API

There are three methods for stopping, restarting, and rescheduling task management.

public static void stopJob(Scheduler scheduler) { try { JobKey jobKey = JobKey.jobKey("testJobId","testJobGroup"); scheduler.pauseJob(jobKey); logger.info("Stop test job ok."); } catch (SchedulerException e) {logger.error(" Stop scheduled task exception!" ,e); } } public static void resumeJob(Scheduler scheduler) { try { JobKey jobKey = JobKey.jobKey("testJobId","testJobGroup");  scheduler.resumeJob(jobKey); logger.info("Resume test job ok."); } catch (SchedulerException e) {logger.error(" Stop scheduled task exception!" ,e); } } public static void rescheduleJob(Scheduler scheduler) { TriggerKey triggerKey = TriggerKey.triggerKey("testJobId","testJobGroup" ); try { CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cornExp); // Rebuild trigger trigger = with the new cronExpression trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); Date rescheduleJob = scheduler.rescheduleJob(triggerKey, trigger); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); JobKey jobKey = JobKey.jobKey("testJobId", "testJobGroup"); Logger.info (jobkey.getName () + "has been rearranged to:" + sdf.format(rescheduleJob) + "and is repeated with the following rules: " + trigger.getCronExpression()); } catch (SchedulerException e) { e.printStackTrace(); }}Copy the code

Execute of Job simulates long tasks

Define a @ DisallowConcurrentExecution annotation, the parallel tasks, sleep was used to simulate long time consuming logic:

@DisallowConcurrentExecution @Component public class MyTestJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { logger.info("Start A job at "+new Date()); if(true) { try { Thread.sleep(300000); logger.info("Finished A job at "+new Date()); } catch (InterruptedException e) { e.printStackTrace(); } return; }}}Copy the code

The test results

Task scheduling is controlled by page, and the state flow process is as follows:

  1. After the application starts and the scheduled time is reached, the task starts to execute.
  2. If the task is hibernated for 5 minutes, run the stop command to stop the task.
  3. Modify the scheduling interval and run rescheduleJob.
  4. Change the system time to before the next schedule time.

The first step is to stop the task from the page within 5 minutes after the task is started and hibernated:Step 2: Start the task again and modify the execution period:Step 3: Change the system time to 11:12 on December 6, 2020-12-6 to see whether the execution period of the next round of tasks has changed.

View the log result:Serial no. ②, ③, and ④ indicate that during the task execution starting at 11:13, although the task is rescheduled to be executed at 11:23The last round is still going onAnd the execution ends at 11:18.

After the time is changed to 11:11 on December 6, the new task will be executed at 11:23, according to the new cycle.

The revelation of

After repeated verification, the conclusion can be drawn: For the currently scheduled and time-consuming task, if the task Angle is redefined by pauseJob, deleteJob and rescheduleJob methods of Scheduler class, the new scheduling policy is invalid for this round of task.

So how do you intervene to terminate a Job that is currently being executed? One idea is to implement InterruptableJob, which polls for interrupt identifiers during execute. However, it does not work for tasks with no circular logic and only a lot of serial computation.