重要的前言
先说说为什么重复造轮子,当时的情况是只需要一个简单的延时任务,做到不丢失即可,引入分布式定时任务框架又觉得太重,因此手动造了个基于redis的简单可靠定时任务。
适用场景,此种做法在单机部署情况下是肯定没问题的,在分布式部署情况下可能会出现问题,比如同一个服务同时重启了,又刚好同时读取redis中的定时任务,还刚好就在那几十毫秒的情况下没有检测到redis锁,此时会导致任务重复读取。
因此,在定时任务的代码中需要容忍可能会出现重复执行的情况,一般做法是用订单状态判断,所以如果不是非常严格的场景,这套做法是够用了 (复杂的定时任务建议用QUARTZ)。
上代码
废话结束,接下来上代码,首先创建定时任务的实体类,保存定时任务执行时间、订单ID、订单类型等。
定时任务实体类
1 | public class DelayedInfo implements Delayed { |
其中delayType、OrderType就是订单类型的枚举标识,可自己定义标识。
定时任务父类
再创建一个定时任务的抽象类,它用来做一些每个定时任务都会有的操作,比如添加定时任务,删除定时任务,扫描redis:
1 | public abstract class DelayService { |
订单定时任务处理类
OK,上面已经建好了父类,接下来可以创建执行业务代码的订单延时任务了,此处我还加了个小功能,那就是执行结果返回true才真的结束任务,如果返回false会再等待一次相同的时间再执行,最多允许失败3次。
1 |
|
创建定时任务执行类
定时任务创建好后需要有个东西来执行它,因此我创建一个循环执行的线程不断判断是否有任务,如果没有任务,该线程阻塞。
1 | /** |
创建定时任务业务处理类
在这里处理你的业务逻辑,代码示例:
1 | /** |
最后一个!添加配置类
我们需要在spring启动完成后执行扫描代码,因此还需要一个配置类
1 |
|
大功造成,在代码中动态添加定时任务的用法如下,只需注入并调用add方法即可:
1 |
|
最后redis依赖别忘记加了哦
1 | <dependency> |
- 本文作者: reiner
- 本文链接: https://reiner.host/posts/569a11d6.html
- 版权声明: 转载请注明出处,并附上原文链接