Наш цикл ожидания ждал сам себя 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: он никогда не ищет процесс по командной строке. Именно те циклы, которые мы писали вручную, и подвели нас.

Обновлено: