pgrep -f と pkill -f を SSH で使った結果、ループが自分自身を35時間待ち続けた

オペレーション

10月31日、SSH 経由で小さなループを開始しました。別のマシン上の翻訳ジョブが完了するのを待ち、その後フォローアップジョブを実行するものです。翻訳ジョブはその夜に完了しました。しかし2日後に確認したところ、ループは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 は自身のプロセスを結果から除外しますが、それを起動したシェルは除外しません。そのため、ループが生きている限り、自分自身と一致するものが見つかります。

双子の問題:pkill -f は実行中のシェルを殺す

pkill -f でも同じことが起こり、結果はさらに悪くなります:

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

シェルのコマンドライン自体にパターンが含まれているため、pkill はシェルを殺してしまいます。ワーカーは停止し、二度と起動されません。SSH はエラーメッセージなしで終了コード 255 で終了します。これはクォーティングの問題のように見え、実際、最初はそのように判断しました。

9月から10月末までの間に、私たちは少なくとも12回以上、いずれかのトラブルに見舞われました。再起動が実行されなかったり、チェックを3時間半も保持するループがあったり、別のループが翻訳キューを50分間保持したり、そしてこのケースもありました。

現在の対処法

私たちのマシンを稼働させるキットである Factory Floor は、systemd ユニットを通じて動作します。コマンドラインでプロセスを探すことは決してありません。私たちを苦しめたのは、手動で入力したループでした。

更新済み: