最近我在对项目的定时任务服务升级,希望改造成分布式,原本是利用@Scheduled注解实现,然而它并不支持分布式,如果改成quartz或者Spring Cloud Task,感觉对于自己这个简单的项目也没有必要。因此,我准备手写一个简单的支持分布式定时调度任务的框架。

项目地址是https://github.com/death00/dis-schedule,欢迎大家star、提意见。

分析

先分析了一下自己的项目,全都是用的cron表达式,因此执行时间点都是固定的,如果升级为分布式的话,肯定是希望在同一个时间点只有一个应用去执行定时调度。

场景就变成了:

多个应用在同一个时间都尝试去执行任务,但最终只有一个应用真正执行。

这样的话,立马就会让人联想到使用去解决,因为是多个应用,所以就是分布式锁。那么,场景又变了:

多个应用在同一个时间都尝试去获取分布式锁,只有一个应用能抢到这把锁,抢到锁的应用可以执行定时任务,其他应用则直接放弃,等待下一次执行时间。

抢锁的时机是每次定时任务执行之前,这又让我联想到了AOP,那么利用注解也就顺理成章了。

分布式锁

既然谈到了分布式锁,那么就想一下,这把锁的名称构成是什么。因为定时任务都有自己专门的时间,如果仅仅采用时间的话,那么当有两个任务同时执行时,则就是在抢一把锁,这同样是不合理的。

所以,锁的名称由两部分组成:任务执行时间、任务名称。

实现

实现方案其实已经很成熟了,可以利用Redis数据库Zookeeper等,Redis用的命令是setNx数据库一般都是利用的唯一索引Zookeeper这点我也不是很了解(如果有感兴趣的同学,欢迎在我的项目中添加)。

我的项目中实现了Redis数据库两种方式,可以看类DisScheduleRedisServiceImplDisScheduleMongodbServiceImpl

注解

其次,我自定义了一个注解DisSchedule

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DisSchedule { /**
* 定时调度任务的名称(默认是方法名)
*/
String name() default ""; /**
* 任务的间隔时间
*/
int duration(); /**
* duration的时间单位(默认:分钟)
*/
DisScheduleUnit unit() default DisScheduleUnit.MINUTES;
}
  1. name代表此次定时调度任务的名称。
  2. duration代表任务的间隔时间,配合unit
  3. unit是自定义的时间单位,有秒、分钟。

该注解需要配合@Scheduled共同使用,例如:

    @DisSchedule(name = "testSchedule", duration = 1, unit = DisScheduleUnit.MINUTES)
@Scheduled(cron = "0 0/1 * * * ?")

cron表达式代表1分钟执行一次,且是在整数分钟开始的时候执行,因此@DisSchedule也需要设置为1分钟的时间。

切面

接下来,我们只需要在Aspect中定义好切入点(有注解@DisSchedule的方法上),针对这些方法,需要使用Around(环绕增强)进行拦截,因为当抢不到锁的时候,就不允许执行。

具体可以参考类DisScheduleAspect

总结

以上就是我实现的简单的分布式定时任务,虽然简单,但应该可以满足你的基础需求,接下来,我会在这个之上,逐步增加功能(比如监测、失败后预警等)。如果你有什么想法,欢迎在下方留言。

有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。

https://death00.github.io/

最新文章

  1. EasyUI TextBox的onkeypress事件
  2. html5 图片上传,支持图片预览、压缩、及进度显示,兼容IE6+及标准浏览器
  3. Maven之Hello World入门实例
  4. 设计模式C#实现(九)——工厂方法模式和简单工厂
  5. Log4Net异常日志记录在asp.net mvc3.0的应用(转载)
  6. IDEA 创建Java Web项目
  7. 【转】ChainMapper 实例理解一
  8. 看人家如何拿到腾讯阿里的offer
  9. jquery批量设置属性readonly和disabled
  10. HDU-1584 蜘蛛牌(dfs)
  11. CoInitialize()、CoInitializeEx()和AfxOleInit()区别联系
  12. 【安全】requests和BeautifulSoup小试牛刀
  13. HDU_1401——同步双向BFS,八进制位运算压缩,map存放hash
  14. SVN的命令解析(感觉不错就转了)
  15. 关于产品的一些思考——腾讯之QQ音乐
  16. springboot~为Money类型添加最大值和最小值的注解校验
  17. pycharm如何在debug的时候动态执行python语句
  18. MyBatis之自查询,使用 递归实现 N级联动
  19. 5 Techniques To Understand Machine Learning Algorithms Without the Background in Mathematics
  20. RemoveDuplicatesfromSortedArray

热门文章

  1. Java集合框架之TreeMap浅析
  2. MSIL实用指南-逻辑运算
  3. Git 上传本地项目到Github
  4. MySQL8版本密码重置(老版本skip-grant-tables不起作用,MySQL服务开启之后立马关闭)
  5. 从零开始开发IM(即时通讯)服务端
  6. iOS8 新特性
  7. 2019dx#9
  8. HYSBZ - 4016 最短路径树问题 点分治 + 最短路径最小字典序
  9. 【Offer】[4] 【二维数组中的查找】
  10. 在asp.net core中使用托管服务实现后台任务