生产环境Sidekiq任务仅首次执行成功,后续直接进入历史队列未执行求助
排查Sidekiq Worker生产环境仅能执行一次的问题
根据你的描述,这问题确实挺棘手——本地跑完全正常,生产环境却只能触发一次Worker任务,之后直接进历史队列连执行痕迹都没,连错误日志都找不到。结合你给出的环境信息和Worker代码,我整理几个优先级较高的排查方向:
1. 优先排查sidekiq-unique-jobs的锁残留问题
你的Worker配置了lock: :until_executed,这个锁的逻辑是任务执行完成前会一直持有锁。如果第一次任务执行时锁的Key没有正常释放(比如Worker进程意外终止、Redis锁Key残留),后续任务检测到锁存在就会直接被拦截,进入历史队列而不执行。
- 验证方法:
- 登录生产环境Redis,执行命令:
KEYS "uniquejobs:*",查看是否有和ImportWorker相关的锁Key残留。如果有,用DEL [锁Key]删掉后再测试导入功能。 - 临时修改Worker配置,把
lock: :until_executed注释掉,或者改成lock: :while_executing,测试是否能重复执行任务——如果可以,那百分百是锁机制的问题。 - 检查
sidekiq-unique-jobs(6.0.15)和sidekiq-pro(5.0.1)、sidekiq(6.0.5)的兼容性,这个版本组合可能存在锁释放的Bug,尝试升级sidekiq-unique-jobs到更稳定的版本(比如6.1.x系列)。
- 登录生产环境Redis,执行命令:
2. 确认Sidekiq进程的队列监听状态
你指定了专用队列import_worker,要确保生产环境的Sidekiq进程真的在监听这个队列:
- 检查Cloud66的Sidekiq启动命令,是否包含
-q import_worker参数?比如正确的启动命令应该类似:sidekiq -q import_worker -q default。如果进程没监听这个队列,任务会被跳过直接进入历史队列。 - 查看生产环境Sidekiq的日志,搜索是否有
Processing import_worker相关的日志条目,确认第一次执行后,后续任务有没有被进程拾取的记录。 - 尝试在Cloud66后台重启Sidekiq进程,有时候进程看似正常但已经卡住,重启后能恢复队列监听能力。
3. 给Worker加日志,确认是否真的没执行
虽然你说Worker逻辑从未执行,但有可能是执行了但没走到核心逻辑(比如找不到Import记录),只是没日志所以误以为没执行:
- 在
perform方法开头加日志:def perform(import_id) Rails.logger.info "ImportWorker started with import_id: #{import_id}" import = Import.find_by(id: import_id) Rails.logger.info "Found import: #{import.inspect}" return if import.blank? # ... 后续代码 - 在
path = import.file.expiring_url(10)和file = open(path)后面也加日志,确认临时URL生成和文件下载是否正常——生产环境的云存储权限、网络限制可能导致这一步失败,但因为没有抛出异常,任务直接结束进入历史队列。
4. 排查Redis的深层问题
虽然Sidekiq.redis { |conn| conn.ping }返回PONG,但还要确认:
- 执行
INFO memory查看Redis内存使用情况,如果内存使用率接近上限,可能导致锁Key无法正常写入/删除。 - 检查ElastiCache的安全组配置,是否允许应用服务器执行
DEL等关键命令?(虽然第一次执行正常,但不排除后续锁释放时命令被拦截)
5. 其他可能的点
sidekiq-limit_fetch的队列并发限制:如果import_worker队列的并发数被设为1,且第一次任务未正常结束,后续任务会排队,但你说直接进历史队列,这个可能性较低,但可以检查配置确认。- 邮件发送环节卡住:
send_mail里用了deliver,如果生产环境邮件服务超时,可能导致任务未正常结束,锁无法释放。可以临时注释掉邮件发送代码,测试任务是否能重复执行。
内容的提问来源于stack exchange,提问作者Diego Marino
相关产品推荐
相关产品推荐

