如何清除卡住/陈旧的 Resque 工作人员?
Posted
技术标签:
【中文标题】如何清除卡住/陈旧的 Resque 工作人员?【英文标题】:How do I clear stuck/stale Resque workers? 【发布时间】:2011-11-16 23:53:50 【问题描述】:正如您从所附图片中看到的那样,我有几个工人似乎被困住了。这些过程不应超过几秒钟。
我不确定为什么它们不会清除或如何手动删除它们。
我在 Heroku 上使用 Resque 和 Redis-to-Go 和 HireFire 来自动扩展工作人员。
【问题讨论】:
嗨,半相关的问题:您是如何通过 heroku 获得 resque-web 仪表板的?我似乎无法弄清楚如何打开它。 【参考方案1】:这些解决方案都不适合我,我仍然会在 redis-web 中看到:
0 out of 10 Workers Working
最后,这对我来说是清除所有工人的工作:
Resque.workers.each |w| w.unregister_worker
【讨论】:
这对我有用。它注销了 all 工人,这有点烦人。但这之后是heroku restart
似乎可以解决问题。它现在显示正确的工人数量。
这将工作人员从 Web 界面中取出,但实际上它们仍然显示为进程,并且还从队列中“窃取”了作业
如果您只想注销不是实际进程的工作人员(也可能是处理作业),您可能想尝试Resque.workers.each |w| matches = w.id.match(/^[^:]*:([0-9]*):[^:]*$/); pid = matches[1]; w.unregister_worker unless w.worker_pids.include?(pid.to_s)
,它只会注销那些 pid 不属于已知进程的工作人员运行 pid。我不知道这是否适用于所有环境,但它在 ubuntu 上运行良好。这可能仅在您的工作人员在您运行此代码的同一台机器上时才有效。
作为选项 Resque.workers.map &:unregister_worker
请注意,这不会摆脱工作进程。【参考方案2】:
在您的控制台中:
queue_name = "process_numbers"
Resque.redis.del "queue:#queue_name"
否则,您可以尝试将它们伪装成已完成删除它们,方法是:
Resque::Worker.working.each |w| w.done_working
编辑
很多人都支持这个答案,我觉得人们尝试使用 hagope 的解决方案很重要,该解决方案将工作人员从队列中注销,而上面的代码会删除队列。如果你乐于伪造它们,那就太酷了。
【讨论】:
如果他这样做会删除整个队列,他只是想删除卡住的那些.. 小更新:你现在必须使用 Resque.redis.del 而不是 Resque.redis.delete 现在实际上有一个 Resque.remove_queue() 方法【参考方案3】:您可能已经安装了 resque gem,因此您可以打开控制台并获取当前工作人员
Resque.workers
它返回一个工人列表
#=> [#<Worker infusion.local:40194-0:JAVA_DYNAMIC_QUEUES,index_migrator,converter,extractor>]
选择工人和prune_dead_workers
,例如第一个
Resque.workers.first.prune_dead_workers
【讨论】:
实际上,在第二次尝试时,这没有任何作用。 这非常适合清除那些在没有取消注册的情况下被杀掉的resque工人。 这似乎是新的最佳答案,因为它不会取消注册所有这些。 prune_dead_workers 不应该是一个类方法吗?但无论如何,很好的解决方案!谢谢。 这绝对是杀死 -9 工人的解决方案。我唯一要补充的是,您需要在使用 -9 杀死的同一台服务器上执行此操作。 一次性对所有人进行:Resque.workers.each(&:prune_dead_workers)【参考方案4】:补充 hagope 的回答,我希望能够只注销已经运行了一段时间的工人。下面的代码只会取消注册运行超过 300 秒(5 分钟)的工作人员。
Resque.workers.each |w| w.unregister_worker if w.processing['run_at'] && Time.now - w.processing['run_at'].to_time > 300
我正在收集与 Resque 相关的 Rake 任务,我也将其添加到:https://gist.github.com/ewherrmann/8809350
【讨论】:
显示如何通过 processing['run_at'] 访问作业开始时间的点。我见过使用 .started 方法的其他解决方案,但这实际上返回了 worker 启动的时间,而不是作业,这是清除卡住的工人的错误方法。谢谢!【参考方案5】:在您运行命令启动服务器的任何位置运行此命令
$ ps -e -o pid,command | grep [r]esque
您应该会看到如下内容:
92102 resque: Processing ProcessNumbers since 1253142769
记下我的示例中的 PID(进程 ID)它是 92102
然后您可以退出进程 1 of 2。
优雅地使用QUIT 92102
强制使用TERM 92102
* 我不确定语法是QUIT 92102
还是QUIT -92102
如果您有任何问题,请告诉我。
【讨论】:
在 Linux 控制台中:kill -SIGQUIT 92102【参考方案6】:我刚刚做了:
% rails c production
irb(main):001:0>Resque.workers
得到工人名单。
irb(main):002:0>Resque.remove_worker(Resque.workers[n].id)
... 其中 n 是不受欢迎的工人的从零开始的索引。
【讨论】:
【参考方案7】:我有一个类似的问题,Redis 将数据库保存到包含无效(非运行)工作人员的磁盘。每次启动 Redis/resque 时,它们都会出现。
使用以下方法修复此问题:
Resque::Worker.working.each |w| w.done_working
Resque.redis.save # Save the DB to disk without ANY workers
确保重新启动 Redis 和 Resque 工作线程。
【讨论】:
【参考方案8】:最近开始研究https://github.com/shaiguitar/resque_stuck_queue/。这不是解决卡住工人的解决方案,但它解决了重新挂起/被卡住的问题,所以我认为它可能对这个线程上的人有所帮助。来自自述文件:
“如果 resque 在特定时间范围内没有运行作业,它将触发您选择的预定义处理程序。您可以使用它来发送电子邮件、寻呼机任务、添加更多 resque 工作人员、重新启动 resque、发送给您一个 txt……随便你。”
已在生产中使用,到目前为止对我来说效果很好。
【讨论】:
【参考方案9】:以下是如何通过主机名从 Redis 中清除它们。当我停用服务器并且工作人员没有正常退出时,就会发生这种情况。
Resque.workers.each |w| w.unregister_worker if w.id.start_with?(hostname)
【讨论】:
【参考方案10】:我遇到了这个问题,并开始在此处实施许多建议。然而,我发现造成这个问题的根本原因是我是using the gem redis-rb 3.3.0。降级到 redis-rb 3.2.2 可以防止这些工作人员首先陷入困境。
【讨论】:
【参考方案11】:我已经直接从 redis-cli 中清除了它们。幸运的是 redistogo.com 允许从 heroku 之外的环境进行访问。 从列表中获取死工人 ID。我的是
55ba6f3b-9287-4f81-987a-4e8ae7f51210:2
直接在redis中运行这个命令
del "resque:worker:55ba6f3b-9287-4f81-987a-4e8ae7f51210:2:*"
您可以监控 redis db 以查看它在幕后所做的事情。
redis xxx.redistogo.com> MONITOR
OK
1380274567.540613 "MONITOR"
1380274568.345198 "incrby" "resque:stat:processed" "1"
1380274568.346898 "incrby" "resque:stat:processed:c65c8e2b-555a-4a57-aaa6-477b27d6452d:2:*" "1"
1380274568.346920 "del" "resque:worker:c65c8e2b-555a-4a57-aaa6-477b27d6452d:2:*"
1380274568.348803 "smembers" "resque:queues"
倒数第二行删除worker。
【讨论】:
不是一个好主意。这不会在 Resque 中调用 unregister 钩子,不会调用失败和可能的清理代码。 这在 2 年前的 resque 中很有用,当时它显示了无法使用界面删除的卡住作业,并且在 rails 中没有干净的方法可以做到这一点【参考方案12】:在 resque 2.0.0 中,似乎有一种方法可以在 resque 2.0.0 中仅移除实际上已死的工人:
Resque::Worker.all_workers_with_expired_heartbeats.each |w| w.unregister_worker
我不是这方面的专家,可能有更好的方法可以做到这一点,或者这会出现问题。我也只是想弄清楚这一点。
这似乎会从 resque 工作人员列表中删除未发送“心跳”的工作人员比预期的时间长得多。
如果幻影工作者处于“运行”状态,则将在“失败”作业队列中创建与幻影作业对应的新条目。
【讨论】:
【参考方案13】:我在这里也有卡住/陈旧的 resque 工人,或者我应该说“工作”,因为工人实际上仍然在那里并且运行良好,这是卡住的分叉进程。
我选择了残酷的解决方案,即通过 bash 脚本杀死分叉进程“处理”超过 5 分钟,然后工作人员在队列中生成下一个,一切继续进行
在这里查看我的脚本:https://gist.github.com/jobwat/5712437
【讨论】:
【参考方案14】:如果您使用的是较新版本的 Resque,则需要使用以下命令,因为内部 API 已更改...
Resque::WorkerRegistry.working.each |work| Resque::WorkerRegistry.remove(work.id)
【讨论】:
【参考方案15】:只要您的 resque 版本比 1.26.0 更新,就可以避免该问题:
resque: env QUEUE=foo TERM_CHILD=1 bundle exec rake resque:work
请记住,它不会让当前正在运行的作业完成。
【讨论】:
【参考方案16】:如果你使用 Docker,你也可以使用这个命令:
<id>
是工作人员 ID。
docker stop <id>
docker start <id>
【讨论】:
以上是关于如何清除卡住/陈旧的 Resque 工作人员?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不清除整个队列的情况下从 Resque 队列中删除特定作业?