集群环境下如何防止定时任务重复执行?

Posted xunianchong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集群环境下如何防止定时任务重复执行?相关的知识,希望对你有一定的参考价值。

起因 
最近做项目是遇到这样一个问题:系统需要在每天的16:00向一些符合特定条件的用户发送一份邮件,发送成功后修改掉数据库中对应数据的标志位。本来是没有问题的,但后来系统被部署到了集群环境下,导致每天会向这些用户发送多次同样的数据,遭到了客户的抱怨。 
解决 
下面来介绍一下处理这种问题的解决办法: 
1.在数据库中建立tm_job_group表

NameTypeComments
group_id number 组id
interval number 时间间隔
区分定时任务的间隔
即多长时间内不可重复执行,单位分钟
remark varchar2(100) 描述

数据如下:

group_idintervalremark
1 1440 24小时执行一次
2 60 1小时执行一次
3 120 2小时执行一次

2.在数据库中建立一张tm_job表,用来存储定时任务的信息

NameTypeComments
job_id number 定时任务的id
job_name varchar2(100) 定时任务的名称
job_group number 定时任务所属的组
remark varchar(100) 备注

数据如下:

job_idjob_namejob_groupremark
1 催办邮件发送Job 1 每天16点执行

3.建立ts_job_log表

NameTypeComments
job_log_id number job的logId,自增
job_id number 定时任务id
job_group number 定时任务所属的组
job_start_time date 执行时间
job_status varchar2(10) 状态 执行情况
job_msg varchar2(100) 备注

这三张表的外键关联可以自己设定,这里就不写了。 
然后为ts_job_log表添加如下的约束:

create  unique  index   idx_ts_job_log_starttime   on  ts_job_log(job_id,decode(job_group,1,to_char(job_start_time,‘yyyymmdd‘),2,to_char(job_start_time,‘yyyymmddhh24‘),3,trunc(to_char(job_start_time,‘yyyymmddhh24‘)/2)),TO_CHAR(JOB_START_TIME,‘DD-MON-RR‘))

这个约束表示 当job_group为1时,在同一天不可以存在两个一样的job_id,当job_group为2时,在同一小时内不可存在两个相同的job_id,job_group为3时,在两个小时内不能出现同样的job_id. 
时间比较的是job_start_time的时间间隔。

在执行定时任务的操作时,先向数据表中insert一条数据,如: 
insert into ts_job_log(job_log_id,job_id,job_group,job_start_time,job_status) 
values(1,1,1,sysdate,’正常’); 
可以添加成功 
当再执行如下操作时 
insert into ts_job_log(job_log_id,job_id,job_group,job_start_time,job_status) 
values(2,1,1,sysdate,’正常’); 
会报错 
如果在代码中捕获到错误就不执行定时任务中的操作。

总结 
这种方法就是通过让数据库中的操作受到约束条件产生异常来实现的。

以上是关于集群环境下如何防止定时任务重复执行?的主要内容,如果未能解决你的问题,请参考以下文章

集群环境下定时调度的解决方案之Quartz集群

Spring+Quartz集群环境下定时调度的解决方案

spring中定时器每周执行两次

spring quartz定时任务集群环境下如何实现只在单个节点运行

集群环境下定时任务调度问题与方案探讨

Spring的quartz定时器到时间后,任务重复执行了两次