Redis分布式锁 + Spring原生定时任务

前段时间,上手了一个新项目,项目中涉及到一些定时任务,常规的非单机项目的定时任务应该是要使用XXLJob或Quartz框架单独写一个定时任务服务来提供定时调度的能力,但项目新、时间赶、任务重,直接就用原生的Spring定时任务来顶上去了,主要的精力还是花在业务开发上,但后续问题就出来了。

主要问题还是在任务重复执行上。在开发环境时,由于只开启了本地服务,而测试环境只有一个节点,并没有发现这个问题,但服务发布到预生产环境,面对三个节点时,问题就暴露了:在到达定时任务的执行时间时,三个节点都会同时执行定时任务,导致了任务重复执行。

后面针对这种情况,有以下两种处理方案:

  1. 对于只是进行数据库数据插入的操作的定时任务,通过对数据库字段增加唯一索引的限制条件,保证结果的最终一致性;
  2. 对于除了数据插入、还包括其他操作的定时任务,例如调用外部接口等,使用redis分布式锁。这与之前做的分布式锁防止多节点并发操作的思想很相像,都是通过锁的思想,来限制同一资源同时被多个线程进行操作。

具体代码示例:

try {
                //锁等待时间 1s,锁持有时间看门狗默认30s
                lock = cacheUtil.lock(MODULE_CODE, lockKey, 1000L, -1L, TimeUnit.MILLISECONDS);
                if (lock) {
                    log.info("监控面板消息通知-获取锁成功,key:{}", lockKey);
                    //再次查库,判断状态,如果被其他定时任务执行了,则无需重复执行
                    Record dbRecord = recordDao.selectById(record.getId());
                    if (dbRecord == null || dbRecord.getSendStatus() != 0) {
                        return;
                    }
                //============= 定时任务执行代码 ==============
}catch (InterruptedException e){
                log.error("获取锁失败,手动设置线程中断", e);
                Thread.currentThread().interrupt();
                record.setSendStatus(2);
                record.setSendFailReason(e.toString());
            }catch (Exception e){
                log.error("消息发送,未知异常", e);
                //未知异常直接失败
                record.setSendStatus(2);
                record.setSendFailReason(e.toString());
            }finally {
                //保存数据
                if (recordModify){
                    recordDao.updateById(record);
                }
                //释放锁
                if (lock){
                    if (cacheUtil.isLocked(MODULE_CODE, lockKey)){
                        try {
                            cacheUtil.unLock(MODULE_CODE, lockKey);
                            log.info("消息通知-释放锁成功,key:{}", lockKey);
                        } catch (InterruptedException e) {
                            log.error("消息通知----------释放锁异常", e);
                        }
                    }
                }
}                

当然这只是迫不得已的处理方式,后续还是会单独开发调度器服务。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值