@SnapLock注解下多实例定时任务重复执行问题排查
多实例下snap-scheduler分布式锁失效排查方案
针对你在Railway部署两个实例后,snap_lock表出现同一定时任务方法的两条执行记录的问题,以下是具体排查方向和验证步骤:
1. 数据库与Schema一致性检查
首先确认两个实例是否操作同一数据库的同一Schema:
- 对比两个实例的
spring.datasource.hikari.schema配置值,PostgreSQL对Schema名称大小写敏感(未用双引号包裹时默认小写),确保完全一致; - 直接连接数据库执行查询:
查看两条记录的SELECT * FROM snap_lock WHERE task_key = 'REPORT_CURRENT_TIME';task_method字段是否完全相同。如果task_method不同,说明snap-scheduler对方法的标识生成存在差异(比如代理类、类加载器导致全限定类名不一致)。
2. 分布式锁原子性验证
snap-scheduler的数据库锁依赖原子性的INSERT/UPDATE操作避免并发插入:
- 检查snap-scheduler版本是否支持
INSERT ... ON CONFLICT DO UPDATE逻辑(这是PostgreSQL实现分布式锁的标准原子操作); - 验证snap_lock表的主键约束是否生效:
确认主键是SELECT conname, conkey FROM pg_constraint WHERE conrelid = 'snap_lock'::regclass;(task_key, task_method),确保同一任务的同一方法无法插入重复记录。
3. 时区一致性排查
定时任务和锁过期时间依赖时区统一,若两个实例时区不一致会导致锁判断失效:
- 在代码中添加日志验证JVM时区:
确认两个实例均为log.info("JVM TimeZone: {}", TimeZone.getDefault().getID());Europe/Kiev; - 验证数据库时区:
确保数据库时区与JVM时区一致;SHOW timezone; - 对比两条锁记录的
lock_until字段,若时间差对应时区偏移量,说明时区不一致导致锁过期判断错误。
4. 部署环境与配置验证
- 确认两个实例引入的
snap-scheduler版本完全一致,不同版本可能存在锁逻辑差异; - 检查
SnapAppConfig是否正确初始化了数据库锁相关Bean,确保启用的是分布式锁而非本地锁; - 验证Railway部署的两个实例是否共享同一数据库资源,不存在网络隔离或数据库副本导致的独立操作。
5. 方法标识生成问题处理
若排查发现两条记录的task_method不同(比如一个是代理类方法名):
- 将定时任务方法从
protected改为public,避免Spring CGLIB代理生成不同的类方法标识; - 若需保留
protected修饰符,可查看snap-scheduler文档,确认是否支持手动指定task_method标识,或配置忽略代理类的方法签名生成策略。
内容的提问来源于stack exchange,提问作者Mykhaylo Terokhin
相关产品推荐
相关产品推荐

