我们的等待循环自己等了 35 个小时:通过 SSH 使用 pgrep -f 和 pkill -f

运维

10 月 31 日,我们通过 SSH 启动了一个小型循环:等待另一台机器上的翻译任务完成,然后运行后续任务。翻译任务当晚就完成了。两天后我们再次查看时,发现该循环已等待了 35 小时,而后续任务从未运行。

这个循环是什么

ssh build-host 'while pgrep -f "i18n_job.py example.com" >/dev/null; do sleep 30; done; ./follow-up.sh'

pgrep -f 会将模式与每个进程的完整命令行进行匹配。SSH 会将带引号的命令作为 bash -c 'while pgrep -f "i18n_job.py example.com" …' 来执行,而该命令行中包含了此模式。pgrep 会排除自身进程,但不会排除启动它的 shell。因此,只要循环处于活动状态,它就会找到匹配项:即它自身。

它的孪生兄弟:pkill -f 会终止其所在的 shell

pkill -f 也会出现同样的情况,而且后果更糟:

ssh build-host 'pkill -f "worker.py --queue a"; nohup python3 worker.py --queue a &'

Shell 自身的命令行中包含该模式,因此 pkill 会终止 Shell。Worker 被停止且再也不会启动,SSH 以退出码 255 退出且没有错误消息。这看起来像是引号问题,我们第一次也这么认为。

从九月到十月底,我们至少十几次栽进了其中一种坑里:该重启却没重启、某个循环卡住一项检查长达三个半小时、另一个循环卡住翻译队列 50 分钟,还有这一个。

我们目前的工作

Factory Floor 是运行我们机器的套件,它通过 systemd 单元工作:从不通过命令行查找进程。曾让我们吃亏的,正是那些我们手动输入的循环。

已更新: