如何在Heroku环境下检查delayed_job的运行状态?
先别慌,我之前也碰到过几乎一模一样的情况,咱们一步步来排查定位问题:
1. 先看Worker的实时日志,抓现场
Heroku显示worker状态up不代表它真的在正常处理任务,得看看它的日志输出有没有异常。在本地终端跑这个命令:
heroku logs -p worker --tail
这会实时输出worker进程的日志,重点找有没有报错信息——比如数据库连接失败、某个任务抛出未捕获的异常导致进程卡住、依赖包加载失败之类的。我之前踩过坑:一个任务里的第三方API调用超时没做异常处理,直接把worker进程卡得一动不动,但Heroku的进程状态还是显示up。
2. 核对Worker的队列监听配置
有时候worker只被配置了监听特定队列,但你的待执行任务全在默认队列或者其他队列里。先检查你的worker启动命令有没有指定队列:
比如如果Procfile里写的是worker: bundle exec rake jobs:work QUEUE=urgent,那它只会处理urgent队列的任务,其他队列的任务自然会堆积。
你可以在Rails控制台里快速确认任务所在队列:
Delayed::Job.pluck(:queue).uniq
如果发现任务都在非worker监听的队列,就修改启动命令改成监听所有队列:bundle exec rake jobs:work QUEUE=*,或者指定多个队列QUEUE=default,urgent。
3. 手动测试任务执行,排查数据库或代码问题
在Rails控制台里挑一个待执行任务手动运行,看看能不能正常执行:
job = Delayed::Job.first job.invoke_job
如果执行时报数据库相关错误,那大概率是数据库连接池配置不够、或者Heroku数据库实例有临时故障。可以检查config/database.yml里的pool参数,worker的连接池建议设置得比web进程高一点,比如5以上。
4. 先重启Worker试试最基础的修复
有时候进程会进入奇怪的死锁状态,虽然Heroku显示up,但已经停止处理任务了。最简单的办法就是重启worker:
heroku ps:restart worker
我碰到过好几次这种“假活”的情况,重启之后worker立刻开始处理堆积的任务。
5. 排查是不是单个坏任务卡住了整个队列
如果前面几步都没问题,那可能是队列里某一个任务有严重bug,worker处理到它就卡死了。可以先把最早的几个任务标记为失败,看看worker会不会继续处理后面的任务:
# 把前5个任务移到失败队列 Delayed::Job.limit(5).each { |job| job.fail! }
如果worker开始处理后面的任务,就说明被标记的任务里有问题,单独拿出来排查代码就行。
6. 检查Heroku的资源限制
如果用的是Standard-1X这类低配dyno,可能因为内存占用过高或者CPU跑满导致进程变慢甚至卡住。可以查看worker的资源使用情况:
heroku ps:info worker.1
如果内存使用率接近100%,要么升级dyno类型,要么优化任务代码减少内存占用(比如批量处理时不要一次性加载太多数据)。
内容的提问来源于stack exchange,提问作者Stephen

