Простая защита от двойного запуска заданий cron в *nix & *BSD

Хотелось бы поведать Вам о простенькой, но очень полезной штуковине, которая позволит защититься Вам от двойного запуска программ через крон. Или как его еще называют лавинной бомбой.

Представьте, что раз в минуту вы обновляете какой-то кеш, чтобы потом быстренько отдать его паре тысяч пользователей сайта и вдруг пользователей тсало не пара тысяч, а например 10 тыс (это в лучшем случае) или запустился какой-нибудь ежемесячный бекап, попавший на прайм-тайм, кеш сформировался не как обычно за 20 секунд, а за 80, и на 60-й секунде его настигает еще один процесс формирования кеша, который доедает остатки производительности системы или отстатки памяти - результат понятен(не правда ли?).

Что будет в таком сценарии дальше — вопрос весьма интересный. Велика вероятность, что два процесса будут активно мешать друг другу (а если это пара сотен парсеров?) (они ведь работают с одними и теми же объектами), и их общее время выполнения будет отнюдь не в два раза больше, чем обычно, а если и третий настигнет… итд. итп...

Описанная ситуация банальна до неприличия, хотя чаще встречается вырожденный вариант: нет никакого крона, просто в полночь в момент истечения срока годности кеша каждый новый посетитель начинает толстый процесс и сервер превращается в тыкву.
Как разработчик, вы обязаны предусмотреть такой сценарий и защититься от него. Но если Буратино был тупой разработчики вашего ПО не позаботились об этом, спасаться придется самостоятельно.

Я использую простую и удобную утилиту lockrun. Принцип ее работы прост: для каждого процесса она создает файл и вешает на него lock. Как только процесс завершается, лок пропадает. Лок также пропадает в случае внезапной смерти процесса, и нет необходимости проверять pid на существование или делать другие телодвижения. Если процесс запускается повторно, а лок-файл еще не освободился, работа скрипта прерывается и выдается сообщение в STDERR.

Утилита написана на C, так что перед использованием ее придется скомпилировать на целевой машине. Итак, качаем, компилируем и кладем куда надо:

$ wget unixwiz.net/tools/lockrun.c
$ gcc lockrun.c -o lockrun
$ sudo cp lockrun /usr/local/bin/


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

Пример использования:
* * * * * /usr/local/bin/lockrun --lockfile=/tmp/megacache.lockrun -- /path/to/megacache/generator

Собственно команда и параметры lockrun разделяются двумя минусами.

Принимаются следующие параметры:

--lockfile=/path/to/file

Обязательный параметр, задающий имя файла для лока. Если такого файла нет, он создастся автоматически. Разумеется, для каждого задания должен быть свой файл.

--maxtime=N

Время в секундах, отводящееся скрипту на «нормальную» работу. Если скрипт работал дольше, в STDERR будет выведено сообщение, которое cron может отправить вам на почту.

--wait

Если этот параметр указан, lockrun не отменит выполнение скрипта, а будет ждать, пока предыдущий процесс освободит лок.

--verbose

Как всегда, выдача более подробной информации о ходе процесса.

--quiet

Не выдавать сообщений об ошибках. Можно включить, если отказ в запуске задания не является серьезной проблемой.

Разумеется, никто не утверждал, что описанная утилита — единственное решение. Существуют и нативные Linux-утилиты.

Идея позаимствована тут.




Вас также может заинтересовать:

Для платформы Android развивается средство для запуска Windows-приложений на базе Wine