Pull to refresh

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

Configuring Linux *
Хочу рассказать о простом скрипте, позволяющем защититься от двойного запуска заданий cron.

Допустим, раз в минуту вы обновляете некий кеш, чтобы стремительно отдать его миллионам посетителей сайта. Все идет прекрасно, но ровно до тех пор, пока глубокой ночью не запустится еженедельный бэкап и ваш кеш сформируется не за 10 секунд, а за 70, и на 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
Не выдавать сообщений об ошибках. Можно включить, если отказ в запуске задания не является серьезной проблемой.

Вот и все. Как видите, действительно просто и эффективно.

UPD: В комментариях мне сообщили, что есть также родное средство для Linux.
Разумеется, никто не утверждал, что описанная утилита — единственное решение.
Tags:
Hubs:
Total votes 61: ↑50 and ↓11 +39
Views 23K
Comments Comments 71