Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумСкрипты и автоматизация

Скрипт-сторож: следит за прогоном и перезапускает

zapuskator
zapuskator
Участник
сообщений 420
с ноя
22 декабря, 17:47первое сообщение

Прогон иногда встаёт молча: процесс живой, в списке висит, а работа не идёт. Написал сторожа на bash, гоняю раз в пять минут из cron:

#!/bin/bash
if ! pgrep -f progon.py > /dev/null; then
  nohup python3 /opt/progon/progon.py >> /var/log/progon.log 2>&1 &
fi

Полное падение он ловит. Как поймать случай, когда процесс висит и ничего при этом не делает?

Денис Прошин
Денис Прошин
Знаток
сообщений 1000
с июн
1 мая, 08:04#2

По живости процесса такое не поймается никогда. Нужен признак работы, который сам прогон обновляет.

Самое дешёвое: файл-биение. Прогон трогает его после каждой обработанной пачки, сторож смотрит на возраст файла.

BIENIE=/run/progon.beat
TIHO=$(( $(date +%s) - $(stat -c %Y "$BIENIE") ))
if [ "$TIHO" -gt 600 ]; then
  echo "прогон молчит больше десяти минут"
fi

Дальше уже сам решай, убивать сразу или сперва слать уведомление.

zapuskator
zapuskator
Участник
сообщений 420
с ноя
8 октября, 11:21#3
Денис Прошин: признак работы, который сам прогон обновляет

Прикрутил, ловит зависание за десять минут. Осталось разобраться с перезапуском, чтобы не наплодить копий.

Тимур Ш.
Тимур Ш.
Участник
сообщений 890
с июн
15 марта, 14:38#4

Перезапуск без замка это отдельная беда: сторож поднял второй экземпляр, первый в этот момент ожил, и оба пишут в один файл выгрузки.

Ставь flock на весь сторож целиком:

exec 9>/run/storozh.lock
flock -n 9 || exit 0

И перед стартом гаси старое по группе процессов, иначе останутся дети от прошлого запуска: pkill -f progon.py; sleep 2.

бэкап перед правкой конфига
Полина Ждан
Полина Ждан
Новичок
сообщений 120
с мая, второй сезон
22 августа, 17:55#5

а systemd такое сам не умеет? я думала там есть watchdog

gremlin_dv
gremlin_dv
Знаток
сообщений 1840
с мар
1 января, 08:12#6

Умеет, и получается честнее самописного сторожа на cron.

Механизма там два, они про разное. Первый простой: Restart=on-failure поднимает упавшую службу, а карусель бесконечных перезапусков придерживают StartLimitIntervalSec со StartLimitBurst, когда причина падения никуда не делась.

Второй как раз про зависание. Служба объявляет WatchdogSec и дальше обязана сама регулярно докладывать, что жива. Перестала докладывать, systemd её убивает и поднимает заново.

[Service]
Type=notify
ExecStart=/opt/progon/progon.py
WatchdogSec=120
Restart=on-failure
RestartSec=15
StartLimitIntervalSec=600
StartLimitBurst=4

В самом скрипте нужен доклад из рабочего цикла:

from systemd.daemon import notify
notify("READY=1")
# после каждой пачки
notify("WATCHDOG=1")

Разница с внешним сторожем вот в чём: доклад идёт изнутри цикла. Встал цикл на сетевом чтении без таймаута, доклад прекратился, служба уехала в перезапуск сама. Файл-биение делает ровно то же самое, просто руками и с задержкой на тик cron.

три монитора и ни одного свободного
zapuskator
zapuskator
Участник
сообщений 420
с ноя
8 июня, 11:29#7

Собрал по итогам ветки. Сторожа из cron убрал совсем, перевёл прогон на службу с Type=notify и докладом после каждой пачки, WatchdogSec поставил вдвое больше самой долгой пачки, StartLimitBurst на четыре попытки. Замок пригодился в другом месте, на ручном запуске из консоли.

Полина, спасибо за наводку, про watchdog внутри systemd я правда не знал.