This is the 13th day of my participation in the First Challenge 2022

The basic concept

  • JavaThere are several ways to implement scheduled tasks in:
    • Timer: Java.util. Timer, a tool that comes with the JDK to handle simple scheduled tasks
    • ScheduledExecutorService: Java. Util. Concurrent ScheduledExecutorService, timing task interface in the JDK, timing task can be used to combine with the thread pool
    • Sceduled: org. Springframework. Scheduling. The annotation. Scheduled, in the Spring framework to achieve timing task based on the annotation approach
    • Quartz: An open source framework that supports distributed scheduling tasks
  • Quartz:
    • Quartz is a powerful open source job scheduling library that can be integrated into the smallest standalone applications to the largest e-commerce programs
    • Quartz can perform thousands of tasks by creating simple and complex plans
    • Any task standard Java component can perform the corresponding programming operation
    • Quartz Scheduler supports JTA transactions and clustering
    • Quartz implements many-to-many relationships between tasks and triggers, allowing multiple tasks to be associated with different triggers

Usage scenarios

  • Tasks performed at a point in time, or repeated at regular intervals
  • A persistent task that holds the timing state of a task schedule
  • Task scheduling that effectively manages scheduled tasks
  • Example:
    • Automatically close 30 minutes of unpaid orders
    • Regularly check accounts with third party companies, docking interface, etc
    • Data statistics, such as blog system statistics daily fans, daily reading, etc
    • Activity start notification and activity end notification
    • Automatic repayment on the 25th of each month
    • Weekly or monthly reminders

Characteristics of Quartz

  • Powerful task scheduling function, including rich task scheduling methods to meet the routine and complex task scheduling requirements
  • Flexible application mode supports the combination of task scheduling and multiple tasks, and supports multiple storage modes of scheduling data, including DB and RAM
  • Support for distributed clusters

Quartz

  • Design pattern:
    • Builder model
    • Portfolio model
    • The factory pattern
  • Quartz core elements:The Scheduler is the controller that actually performs the scheduling. Trigger,Job and JobDetail are metadata of task scheduling
    • The task Scheduler Scheduler
    • Trigger the Trigger
    • The Job tasks
    • The task scheduler JobDetail

Scheduler

  • Task schedulerScheduler:
    • Multiple triggers and Jobdetails can be registered in a task scheduling container
    • When Trigger and JobDetail are combined, they can be scheduled by the task Scheduler
    • Typically, an application requires only one Scheduler object
  • SchedulerFactory is used to create a Scheduler:
    • Including DirectSchedulerFactory and StdSchedulerFactory
    • Since DirectSchedulerFactory requires a lot of detailed manual coding design, StdSchedulerFactory is often used
  • SchedulerThere are three main types:
    • RemoteMBeanScheduler
    • RemoteScheduler
    • StdScheduler

Trigger

  • Trigger Trigger: Time rule for task scheduling
  • Trigger is a Quartz Trigger that notifies the task Scheduler to execute the specified task Job
// Specify when the trigger fires for the first time
new Trigger().startAt();
// Specifies when the trigger stops firing
new Trigger().endAt();
Copy the code
  • QuartzFour types of triggers are provided in:
    • SimpleTrigger: Can execute a task once in a specified period of time or multiple tasks in a period of time
    • CronTrigger:
      • Calendar – based task scheduling, very powerful function
      • CronTrigger is more commonly used because it is based on Cron expressions
    • DateIntervalTrigger
    • NthIncludedDayTrigger
  • Calendar:A collection of calendars at specific points in time
    • A trigger can contain multiple calendars, which can be used to include or exclude certain time points

JobDetail

  • Job scheduler JobDetail:
    • A concrete executable task scheduler
    • Job is what the executable task scheduler does
    • JobDetail also contains task scheduling schemes and policies
  • The Job specified by the JobDetail binding. Each time a Job is executed by Scheduler, the corresponding Job is first obtained. Execute () in the Job. After the Job is executed, the associated Job object instances are released and cleared by the JVM’s GC
  • JobDetailforJobInstances provide a number of attributes:
    • name
    • group
    • jobClass
    • jobDataMap

Job

  • Task Job:Represents specific work to be performed or a scheduled task
    • Custom task classes need to implement this interface by overriding the execute() method to define the execution logic of the task
  • JobThere are two types of:
    • Stateless Job
    • statefulstateful job
      • For the same Trigger, stateful jobs cannot be executed in parallel. Only after the last triggered Job is executed, the next Job can be executed
  • JobThere are two types of attributes:
    • Volatility: Indicates whether the task is persisted to the database store
    • durability:There is notriggerWhether the task is reserved during association
      • In both cases, a value of true indicates that the task is persisted or retained
      • A Job can be associated with multiple triggers, and a Trigger can be associated with only one Job
  • JobExecutionContext:
    • JobExecutionContext contains detailed data about the Quartz runtime environment and the Job itself
    • When a Scheduler executes a Job, the JobExecutionContext is passed to the current Job’s execute() object, and the current Job gets information from the JobExecutionContext object
  • The reason why Quartz is designed as JobDetail + Job is that:
    • The JobDetail is used to define the Job data. The real logic for executing the Job is in the Job
    • Because tasks can be executed concurrently, if a Scheduler uses a Job directly, concurrent access to the same Job instance is a problem
    • By binding JobDetail to a Job, the Scheduler creates a new Job instance based on JobDetail each time, avoiding concurrent access problems

Quartz main thread

  • QuartzThere are two types of threads:
    • The thread of execution
    • Thread scheduling
  • The relationship between the main threads of Quartz:

  • Thread of execution:
    • Typically, the threads executing tasks are maintained using a Thread Pool, Job Thread Pool
  • Scheduling threads:
    • A Regular Thread polls triggers and, if there is a Trigger to be triggered, retrieves an idle Thread from the task Thread pool and executes the Job associated with the Trigger
    • Misfire Scheduler Thread: MisfireThread scans all triggers to see if there is a miss. If there is a miss, the MisfireThread executes according to the specified policy

Quartz data storage

  • Quartz triggers and jobs need to be stored before they can be used
  • QuartzThere are two types of data storage:
    • RAMJobStore
      • Store Trigger and Job in memory
      • RAMJobStore is very fast to access, but all data is lost after the system stops
    • JobStoreSupport
      • The Trigger and Job are stored in the database based on JDBC
      • In cluster applications, JobStoreSupport is required to avoid data loss after the system stops
  • The Quartz cluster is aware of the rest of the application through database tables, with no direct communication between the nodes. Quartz clustering can only be completed using persistent JobStore
  • QuartzIn theSQLLocation:
    • /docs/dbTables
    • org/quartz/impl/jdbcstore
  • Quartz table structure:
The name of the table describe
QRTZ_CALENDARS Store Quartz calendar information
QRTZ_CRON_TRIGGERS Stores Trigger of type CRon

Includes crON expressions and time zone information
QRTZ_FIRED_TRIGGERS Stores status information about triggered triggers and Job execution information
QRTZ_PAUSED_TRIGGER_GRPS Stores information about the paused Trigger group
QRTZ_SCHEDULER_STATE Stores scheduler-related state information
QRTZ_LOCKS Stores pessimistic locking information for the program if it uses pessimistic locking
QRTZ_JOB_DETAILS Store the JobDetail information of each configured JobDetail
QRTZ_SIMPLE_TRIGGERS Stores the Simple Trigger

This includes the number of repetitions, the interval, and the number of times it has been triggered
QRTZ_BLOG_TRIGGERS Store Blog Trigger
QRTZ_TRIGGERS Stores basic information about the configured Trigger
QRTZ_TRIGGER_LISTENERS Stores information about the Trigger listener
QRTZ_JOB_LISTENERS Store Job listener information
  • The Quartz task using cron expressions requires the tables QRTZ_CRON_TRIGGERS, QRTZ_FIRED_TRIGGERS, QRTZ_TRIGGRS, and QRTZ_JOB_DETAILS

Quartz sample

  • QuartzThere are three basic components:
    • The task Scheduler Scheduler
    • Trigger Trigger: Includes SimpleTrigger and CronTrigger
    • The Job tasks
  • You need to define an interface to implement the timing function, that is, Job

  • The basic function of a Trigger is to specify the execution time, execution interval, and running times of a Job

  • Finally, a task Scheduler is defined, which is called Scheduler. The function of the task Scheduler is to combine the Job and Trigger and specify Trigger to execute the specified Job

Quartz dynamic management

  • To the taskJobDynamic management of tasks is actually done in the schedulerSchedulerTask scheduler inJobDetailDo dynamic operations
    • Start with the task scheduler JobDetail
    • Then update the Job in the database synchronously based on the Job JobKey or TriggerKey
  • In order to achieve the taskJobDynamic management of tasksJobYou have to persist it to the database
    • SpringThe container loads all tasks from the database at startupJob
      • Tasks need to be persisted to keep basic information in a database
      • Distributed task
    • Implement CommandLineRunner
    • Define initialization operations
  • Implement the Run () method in the CommandLineRunner interface:
public void run(Strig... strings) throws Exception {
	// Get the Job in the database
	List<JobInfo> jobInfoList = jobInfoMapper.selectAll();
	List<JobInfoVo> jobList = BeanUtils.copyList(jobInfoList, JobInfoVo.class);

	// Synchronize the status of the task Scheduler based on the status of the Job in the database
	for (int i = 0; i < jobList.size; i++) {
		JobInfoVo job = jobList.get[i];
		// Get the Job
		Class jobClass = Class.forName(job.getJobClass());
		/ / get JobKey
		JobKey jobKey = JobKey.jobKey(job.getJobName(), job,getJobGroup());
		/ / get TriggerKey
		TriggerKey triggerKey = TriggerKey.triggerKey(job.getTriggerName(), job.getTriggerGroup());
		
		// Create the specified JobDetail instance and bind it to the specified Job
		JobDetail jobDetail = JobDetailBuilder.newJob(jobClass)
			.withIdentity(jobKey)
			.storeDurably()
			.build();
		// Create the specified trigger instance that fires according to the cron expression
		Trigger trigger = TriggerBuilder.newTrigger()
			.withIdentity(triggerKey)
			.withSchedule(CronSchedulerBuilder
				.cronSchedule(job.getCronExpression()))
			.builder();

		// Synchronize the task Scheduler status based on the Job status
		JobStatus jobStatus = JobStatus.valueOf(job.getJobStatus());
		switch (jobStatus) {
			case RUNNING :
				scheduler.scheduleJob(jobDetail, trigger);
			casePAUSE : scheduler.scheduleJob(jobDetail, trigger); scheduler.pauseJob(jobKey); }}// Add a listener for the Job
	QuartzJobListener jobListener = new QuartzJobListener("jobListener", JobManagerService);
	scheduler.getListenerManager().addJobListener(jobListener, allJobs() );
} 
Copy the code

SpringBoot integration Quartz

  • QuartzUse the basic flow:
    • Start by creating the task Job, which is the body of the task and is used to write the business logic for the task
    • Then create a task Scheduler, which is used to schedule tasks and is mainly used for starting, stopping, pausing and resuming tasks
    • Then create the JobDetail, which is used to store the information related to the task and is bound to the specified Job for the scheduler to execute
    • Then create the Trigger Trigger, which defines the Trigger rules for the task. The main types of triggers are SimpleTrigger and CronTrigger
    • Finally, the task JobDetail and Trigger Trigger are started based on the Trigger Scheduler

Create a Job

  • To create a class that implements the Job interface, you need to override the execute() method, which is the specific business execution logic
  • If it is a dynamic task, you need to dynamically pass in the parameters when creating the task detail JobDetail or Trigger, and then use JobExecutionContext to get the parameters for processing

Create a task Scheduler Scheduler

  • If it is normal, it needs to be created through the task SchedulerFactory SchedulerFactory
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
Copy the code
  • In SpringIOC, injection can be done directly through Spring:
@Autowired
private Scheduler scheduler;
Copy the code
  • Normal mode, created by factory:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
Copy the code

Create JobDetail JobDetail

/* * Get the implementation of the current Job through jobBuilder.newJob (), and then add the task details through the chain call * - fixed Job implementation * - If it is a dynamic implementation, create jobs * - based on different classes Such as ((Job) Class. Class.forname (" com. Oxford. Job. DynamicJob "). The newInstance ()). The getClass () * - Is the realization of a current Job: JobBuilder newJob (((Job) Class. Class.forname (" com. Oxford. Job. DynamicJob ")). The getClass ()) * /
 JobDetail jobDetail = JobBuilder.newJob(Job.class)
 	/* * usingJobData can add arguments to the current JobDetail in k-v format * * usingJobData can be chain-called, passing multiple arguments * In Job implementation class, can pass JobExecutionContext. GetJobDetail () getJobDataMap () get (" name ") for the value of the parameter * /
 	.usingJobData("name"."oxford")
 	// Add authentication information
 	.withIdentity("name"."group")
 	// The task details take effect after they are created
 	.build()
Copy the code

Create Trigger Trigger

  • There are two common types of triggers:
    • SimpleTrigger
    • CronTrigger

SimpleTrigger

  • SimpleTrigger: Sets timed execution rules based on custom methods in the Quartz framework’s classes
Trigger trigger = TriggerBuilder.newTrigger()
	/* * usingJobData can add arguments to the current JobDetail in k-v format * * usingJobData can be chain-called, passing multiple arguments * In Job implementation class, can pass JobExecutionContext. GetJobDetail () getJobDataMap () get (" name ") for the value of the parameter * /
 	 .usingJobData("name"."oxford")
 	 // Add authentication information
 	 .withIdentity("name"."group")
 	 // Add start execution time - startNow()
 	 // Start execution time
 	 .startAt(start)
 	 // End the execution time. If this parameter is not added, the execution is permanent
 	 .endAt(end)
 	 // Add the execution rule. Add a SimpleTrigger trigger using SimpleScheduleBuilder
 	 .withSchedule(SimpleSchedulebuilder
 	 	.simpleSchedule()
 	 	// Execute interval, in this case every 6 seconds
 	 	.withIntervalInSeconds(6)
 	 	.repeatForever())
 	 // The trigger is created. Enforce the
 	 .build();
Copy the code

CronTrigger

  • CronTrigger: Implements triggers based on Cron expressions
Trigger trigger = TriggerBuilder.newTrigger()
	/* * usingJobData can add arguments to the current JobDetail in k-v format * * usingJobData can be chain-called, passing multiple arguments * In Job implementation class, can pass JobExecutionContext. GetJobDetail () getJobDataMap () get (" name ") for the value of the parameter * /
 	 .usingJobData("name"."oxford")
 	 // Add authentication information
 	 .withIdentity("name"."group")
 	 // Add start execution time - startNow()
 	 // Start execution time
 	 .startAt(start)
 	 // End the execution time. If this parameter is not added, the execution is permanent
 	 .endAt(end)
 	 // Add the execution rule. Add a CronTrigger trigger using CronScheduleBuilder
 	 withSchedule(CronScheduleBuilder
 	 	.cronSchedule("0/2 * * * *?"))
 	 // The trigger is created. Enforce the
 	 .build();
Copy the code

Start the task

// Add tasks according to task details and task triggers
scheduler.scheduleJob(jobDetail, trigger);
if(! scheduler.isShutdown()) { scheduler.start(); }Copy the code

Suspended task

// Suspend the task based on the withIdentity authentication information in the trigger
scheduler.pauseTrigger(Trigger.triggerKey("name"."group"));
Copy the code

The restore task

// Restore the task based on the withIdentity authentication information in the trigger
scheduler.resumeTrigger(Trigger.triggerKey("name"."group"));
Copy the code

Delete the task

// Pause the task
scheduler.pauseTrigger(Trigger.triggerKey("name"."group"));
// Then remove the task
scheduler.unscheduleJob(Trigger.triggerKey("name"."group"));
// Delete the task based on the withIdentity authentication information in the task details
scheduler.deleteJob(JobKey.jobKey("name"."group"));
Copy the code
  • An example of a scheduled task with SpringBoot integrated with Quartz