[057][调度模块]分布式环境下定时任务的防重复执行方案

[057][调度模块]分布式环境下定时任务的防重复执行方案

本文章代码: gitee , gitcode , github

摘要

在集群部署中,同一个定时任务可能在多台机器上同时触发,造成资源浪费或数据错误。本文基于提供的 AutoRenewalLockTaskRunner 和 FixedLeaseLockTaskRunner 系列接口,阐述如何利用 Redis/Redisson 分布式锁包装任务执行,确保同一时刻只有一个节点执行任务。

1. 任务接口设计

框架定义了多个锁装饰器接口,业务实现只需继承相应接口并实现 doRun():

// Redis 自动续期锁
public interface AutoRenewalLockTaskRunner extends TaskRunner, Lockable {
    @Override
    default void run(Map<String, String> params) {
        RedisLockService.instance.autoRenewal()
            .doInLock(key(), () -> doRun(params));
    }
    void doRun(Map<String, String> params);
    // key() 定义锁的标识,如 "task:order:sync"
}

类似地,还提供了:

  • FixedLeaseLockTaskRunner(Redis 固定租期)
  • AutoRenewalBlockLockTaskRunner(Redisson 阻塞+自动续期)
  • FixedLeaseReentrantLockTaskRunner(Redisson 可重入+固定租期)

2. 两种锁模式对比

模式 适用场景 Redis 实现 Redisson 实现
固定租期 任务执行时间稳定且较短 SET NX PX + 不续期 lock(leaseTime)
自动续期 任务执行时间不确定或较长 定时任务每 5s 续期 lock()(看门狗机制)

3. 锁的粒度控制

Lockable 接口要求实现类提供 key() 方法,通常按任务名称或业务 ID 区分:

@Override
public String key() {
    return "schedule:lock:" + getTaskName(); // 例如通过构造函数注入
}

4. 异常处理

  • 若获取锁失败(如已被其他节点占用),会抛出 LockCreateException,任务直接跳过,不会影响下次调度。
  • 可覆盖 handleException(LockException) 方法自定义失败处理(如记录日志、发送告警)。

5. 集群效果

所有节点使用相同的锁 key,第一个获得锁的节点执行,其他节点快速失败,保证任务在集群内单点运行。

posted @ 2026-08-06 08:35  杨运交  阅读(5)  评论(0)    收藏  举报