Past recommendation
[RabbitMQ analysis] 01 SimpleMessageListenerContainer principle analysis
[sharding-sphere] - 01 SQL Routing
[Nacos source code analysis] - 02 Obtaining the configuration process
[Java Concurrent Programming] - 03 MESI, memory barrier
[Spring source code]- 11 Programmatic transactions of Spring AOP
overview
Quartz
An open source task scheduling framework with rich functions and a long history, which is completely based on Java. It is very well-known in the field of Java scheduling. Its easy-to-use, stable and reliable features make it regarded as the basic dependency of the scheduling framework by many third-party applications. If it has built-in spring boot
integration quartz
, elastic-job
the scheduling framework will quartz
be packaged as its underlying basic implementation. xxl-job
Historical versions were also integrated quartz
as its trigger The implementation mechanism is basic, but the implementation of the time wheel has been quartz
removed in the latest version.
core trident
When in use quartz api
, the most core three-piece suit is as follows:
Scheduler
SchedulerFactory
And Scheduler
it is easy to identify from the name. The factory design pattern is adopted here, which Scheduler
is quartz
the most important component exposed for development. From the developer's perspective, it is the quartz
facade of the factory. quartz
Various operations are Scheduler
connected in series, similar quartz
to The role of butler and spokesperson.
“This design pattern is very common in open source frameworks, such as
mybatis
Zhonghe , which simplifies the difficultySqlSessionFactory
forSqlSession
developers to get started by providing developers with big housekeeper components and connecting all core functions in series through one component.
Generally, an application only corresponds to one Scheduler
instance, and different Scheduler
instances are isolated through schedulerName
isolation. All quartz
database table designs have this column field, so that the Scheduler will only operate on the corresponding data sched_name
in the database table when processing tasks . Clustering is to use multiple instances to configure the same name, so that multiple machines can process the same task at the same time to achieve the cluster effect.schedulerName
quartz
Scheduler
schedulerName
schedulerName
“
schedulerName
Can beorg.quartz.scheduler.instanceName
configured via , the default name isQuartzScheduler
.
Scheduler
The operation is mainly related JobDetail
to Trigger
two components, JobDetail
which encapsulate task configuration information, and Trigger
triggers encapsulate task trigger information. They are 1:N
relationships, that is, one JobDetail
can be associated with multiple Trigger
triggers, but one Trigger
trigger can only be bound to one job. .
JobDetail
JobDetail
The component encapsulates quartz
the scheduling task definition information, the following is JobDetail
the general usage of the component as follows:
// JobDataMap实现Map接口,任务调度时存储到JobExecuteContext中,可以传递给Job实例
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("name", "zhangsan");
jobDataMap.put("time", System.currentTimeMillis());
JobDetail jobDetail = JobBuilder
// 绑定任务类
.newJob(QuartzCronJob.class)
.storeDurably()
// job对应ID
.withIdentity("job2", "DEFAULT")
.usingJobData(jobDataMap)
.build();
JobKey jobKey = jobDetail.getKey();
if (scheduler.checkExists(jobKey)) {
log.warn("调度任务已存在,删除后重新添加:{}", jobKey);
scheduler.interrupt(jobKey);//停止JOB
/**
* deleteJob操作在删除Job之前,会执行unscheduleJob()取消job和trigger关联
*/
scheduler.deleteJob(jobKey);
}
// 将JobDetail任务定义信息插入quartz表
scheduler.addJob(jobDetail, true);
JobDetail
The operation is relatively simple, and there are two main points to note: 1. newJob(Class <? extends Job> jobClass)
The operation is bound to the task class, which is the class that encapsulates the user's business logic; 2. withIdentity(String name, String group)
Set an identity ID for the task, which can be used for subsequent management, for convenience and flexibility The management quartz
abstracts group
the concept, so that batch operations can be performed on a group of jobs in batches, and the identity ID is used for JobKey
encapsulation.
Use Scheduler
the class addJob(JobDetail jobDetail, boolean replace)
method to add the created Job
definition information to it quartz
. Generally, the database persistence mode is used, that is, Job
the definition information will be inserted into qrtz_job_details
the table here (see the figure below).
Let's look at the following key fields:
sched_name:上面说过,用来关联对应的Scheduler实例
is_durable:是否持久化
is_nonconcurrent:是否允许同一个作业可以同时多个实例执行,比如一个任务间隔1秒,但其执行时间为2秒,通过该属性控制是否允许同一个作业有多个任务同时允许,参见@DisallowConcurrentExecution
is_update_data: 任务已经执行中,是否允许更新JobDataMap持久化信息,参见@PersistJobDataAfterExecution
requests_recovery: 故障恢复使用,具体参见后续源码分析
job_data:JobDataMap序列化后存储到字段中
Trigger
The task definition is complete, but the task is triggered according to the periodic rules, it depends on Trigger
the face of the trigger
Trigger
The general usage of components is as follows:
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("name", "lisi");
jobDataMap.put("address", "China");
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1", "DEFAULT")
.usingJobData(jobDataMap)
.startAt(new Date())
.endAt(new Date(System.currentTimeMillis()+38 * 60 * 1000))
.withSchedule(CronScheduleBuilder.cronSchedule("*/10 * * * * ?"))
.forJob(new JobKey("job1", "DEFAULT"))
.build();//时间
TriggerKey triggerKey = trigger.getKey();
if(scheduler.checkExists(triggerKey)){
scheduler.unscheduleJob(triggerKey);
}
//必须绑定job
scheduler.scheduleJob(trigger);
Similar to and JobDetail
, there are two main points to note: 1. Similarly withIdentity(String name, String group)
, set an identity ID for the trigger in the same way, corresponding to ; TriggerKey
2. startAt()
, corresponding to endAt()
the start and stop time; 3. withSchedule(CronScheduleBuilder.cronSchedule("*/10 * * * * ?"))
; Task.forJob(JobKey keyOfJobToFire)
Trigger
Job
Finally, add the created definition information to it through Scheduler
the class method . Generally, the database persistence mode is used, that is, the definition information will be inserted into the trigger-related table here. In the example using the trigger, it will be inserted into the table (see below picture).scheduleJob(Trigger trigger)
Trigger
quartz
Trigger
cron
qrtz_cron_triggers
Let's take a look at how the task is triggered. Scheduler
After the class scheduleJob(Trigger trigger)
persists the trigger, you will find that qrtz_cron_triggers
there is no start and end time and Job
binding content, so let's look at a very important table: qrtz_triggers
. The method will insert a record into the table at the same time after scheduleJob()
persisting the information (see the figure below):Trigger
qrtz_triggers
qrtz_job_details
And qrtz_cron_triggers
can be regarded as a static table, that qrtz_triggers
is, the running dynamic table, which stores the data during the running of the task and changes dynamically with the running records. It is quartz
the most important table for scheduling task running. Let's take a look at some key points in this table field:
start_time、end_time: trigger定义时设置的起止时间
next_fire_time: 下次触发时间戳
prev_fire_time: 上次触发时间戳
trigger_state: trigger状态,最常见状态WAITING、ACQUIRED和EXECUTING,分别对应等待(下次触发时间还早) -> 加载到内存中等待(下次触发时间快到了) --> 执行(下次触发时间到了,需要触发任务),具体参见后续源码分析
misfire_instr: trigger触发时间过期处理策略,比如本来是10:23:50时间点进行触发,但是由于某些原因在10:23:53秒才检索出来,这是该触发时间点已经过期,misfire_instr就是控制采用什么策略处理该过期任务,是直接丢弃重新计算下次触发时间点、还是一定时间范围内过期的理解执行等等,具体参见后续源码分析
job_data: 和JobDetail一样,Trigger也可绑定一个JobDataMap,用于向Job实例传递参数,该字段就是存储Trigger关联的JobDataMap序列化内容
quartz
Basically, it is to realize the task triggering around these key fields. We can roughly come up with a rough process of the task scheduling trigger mechanism qrtz_triggers
by guessing :quartz
1. Through the configured trigger
trigger, calculate the next trigger time, update to next_fire_time
the field, and update trigger_state
the status as WAITING
;
2. quartz
The thread scans the table, queries the records that will be triggered in a short period of time in the future (comparison next_fire_time
and current time) into the memory queuing queue, and then trigger_state
updates to ACQUIRED
;
3. Then block until the trigger task in the memory queuing queue reaches the time point, before triggering the task, recalculate the next trigger time point, update to, and update to, and then next_fire_time
execute trigger_state
the WAITING
current task;
4. Since next_fire_time
the sum trigger_state
value is updated, start step 1 again, and the triggering cycle continues like this.
Summarize
This section simply analyzes the core operating mechanism from the perspective of a user quartz
. Since it simply analyzes the source code from the outer layer without in-depth analysis, it simply quartz
makes a simple guess about the approximate operating mechanism based on the information in the database table, and some important attributes have not been expanded. Follow these questions in the next section to find the real answer through source code analysis, and deepen quartz
the understanding of the operating mechanism step by step.
Long press the QR code below to identify attention