Наш цикл очікування чекав на себе 35 годин: pgrep -f і pkill -f через SSH

Операції

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 виключає зі своїх результатів власний процес, але не оболонку, яка його запустила. Тому, доки цикл був живий, він знаходив відповідність: себе.

Його близнюк: pkill -f вбиває оболонку, у якій працює

Те саме відбувається з pkill -f, але з гіршими наслідками:

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

Командний рядок самої оболонки містить шаблон, тому pkill вбиває оболонку. Воркер зупиняється і більше не запускається, а SSH завершується з кодом 255 без повідомлення про помилку. Це виглядає як проблема з лапками, і саме так ми сприйняли це вперше.

Між вереснем і кінцем жовтня ми потрапляли в одну з цих ситуацій щонайменше з десяток разів: перезавантаження, які так і не відбулися, цикл, який утримував перевірку три з половиною години, інший, який утримував чергу перекладів 50 хвилин, і цей випадок.

Що ми робимо тепер

Factory Floor, набір, який керує нашими машинами, працює через юніти systemd: він ніколи не шукає процес за командним рядком. Цикли, які нас підвели, були тими, що ми писали вручну.

Оновлено: