优雅地实现定时任务——记住这三点就够

前言

定时任务=调度+执行

调度有很多框架实现:elastic-job、quartz等

执行需要程序员实现任务队列。实现任务队列有很多方式:数据库、redis、kafka

实现任务队列虽然很简单,但稍有不慎,也很容易出问题。

代码实现

 首先把问题简单化,假如需要在单库实现定时任务,我们逐步实现优化代码

第一次实现

public void execute1() {
	List jobEntities = jobEntityMapper.getAllToBeProcess();
	for (JobEntity jobEntity : jobEntities) {
		this.businessProcess(jobEntity);
	}
}

以上代码会有什么问题呢?

内存可能顶不住(如果不走索引,定时任务执行慢)

如何优化?

采用分页、并且sql脚本需要走索引

sql实现分页,也有很多方式,效率不一样,同样需要认真考虑

比如:

select * from table limit m,n;

select * from table order by id limit m;

select * from table_name inner join ( select id from table_name where (user = xxx) limit 10000,10) b using (id)

这三个sql语句就各有优缺点

第二次实现

public void execute2() {
	List jobEntities = jobEntityMapper.getFirstPageToBeProcess();
	while (null != jobEntities && !jobEntities.isEmpty()) {
		for (JobEntity jobEntity : jobEntities) {
			this.businessProcess(jobEntity);
		}
		jobEntities = jobEntityMapper.getNextPageToBeProcess();
	}
}

这一次实现加入了分页功能

这次还存在什么问题呢?

如果第5行代码发生了异常,就会有问题(表象:执行慢、假死 )

第三次实现

public void execute3() {
	List jobEntities = jobEntityMapper.getFirstPageToBeProcess();
	while (null != jobEntities && !jobEntities.isEmpty()) {
		for (JobEntity jobEntity : jobEntities) {
			try {
				this.businessProcess(jobEntity);
			} catch (Exception e) {
				e.getStackTrace();
			}
		}
		jobEntities = jobEntityMapper.getNextPageToBeProcess();
	}
}

这一次加入try_catch捕获异常,这样就没有问题了吗?

答案是否定的

如果第6行代码发生异常,数据没有处理,下一次依旧会被查询出来处理,这样也会执行慢,并且可能假死状态。

第四次实现

public void execute4() {
	List jobEntities = jobEntityMapper.getFirstPageToBeProcess();
	while (null != jobEntities && !jobEntities.isEmpty()) {
		for (JobEntity jobEntity : jobEntities) {
			try {
				this.businessProcess(jobEntity);
			} catch (Exception e) {
				e.getStackTrace();
				updateProcessCount(jobEntity);
			}
		}
		jobEntities = jobEntityMapper.getNextPageToBeProcess();
	}
}

这一次当出现异常的时候,会去更新这条异常数据的处理次数。

所以,定时任务的每一条任务一定要有一个明确的终止条件,包括正常处理的终止条件和异常的终止条件。

异常终止条件有几种实现方式,比如:

  1. 超过一定次数
  2. 超过一定时间
  3. 出现异常删除
  4. 用状态控制(待处理,处理失败)

总结

定时任务实现注意事项

  1. 一定要有分页、并且走索引;
  2. 一定要有异常捕获;
  3. 一定要有明确的正常/异常终止条件。

你可能感兴趣的:(程序人生)