Я запланировал запуск задания cron каждую минуту, но иногда выполнение сценария занимает больше минуты, и я не хочу, чтобы задания начинали «складываться» друг с другом. Я предполагаю, что это проблема параллелизма - т.е. выполнение скрипта должно быть взаимоисключающим.
Чтобы решить эту проблему, я заставил скрипт проверить наличие определенного файла (« lockfile.txt ») и завершить работу, если он существует, или touch
его нет. Но это довольно паршивый семафор! Есть ли лучшая практика, о которой я должен знать? Должен ли я написать вместо этого демон?
источник
flock -n file command
аflock -n file -c command
?-c
запускает указанную команду через оболочку (согласно man-странице), в то время как «голая» (не-c
) форма простоexec
с данной командой , Помещение чего-либо через оболочку позволяет вам делать вещи, подобные оболочке (например, запускать несколько команд, разделенных;
или&&
), но также открывает вам возможности для атак расширения оболочки, если вы используете ненадежный ввод.frequent_cron_job
команды, которая пыталась показать, что она запускается каждую минуту. Я удалил его, так как он не добавил ничего полезного и вызвал замешательство (ваше, если никто не будет за эти годы).Лучший способ в оболочке - использовать flock (1)
источник
99
и>
так оно и есть99> /...
На самом деле,
flock -n
может использоваться вместоlckdo
*, поэтому вы будете использовать код от разработчиков ядра.Основываясь на примере womble , вы бы написали что-то вроде:
Кстати, глядя на код, все
flock
,lockrun
иlckdo
сделать то же самое, так что это просто вопрос , который является наиболее доступным для вас.источник
Вы можете использовать файл блокировки. Создайте этот файл при запуске скрипта и удалите его по завершении. Сценарий, прежде чем запускать свою основную процедуру, должен проверить, существует ли файл блокировки, и действовать соответствующим образом.
Lock-файлы используются initscripts и многими другими приложениями и утилитами в системах Unix.
источник
Вы не указали, хотите ли вы, чтобы скрипт ждал завершения предыдущего запуска или нет. «Я не хочу, чтобы задания начали« складываться »друг над другом», я предполагаю, что вы подразумеваете, что хотите, чтобы скрипт завершился, если он уже запущен,
Итак, если вы не хотите зависеть от lckdo или подобного, вы можете сделать это:
источник
Это также может быть признаком того, что вы поступаете неправильно. Если ваши задания выполняются так часто и часто, возможно, вам следует подумать о том, чтобы свернуть их и сделать из них программу в стиле демона.
источник
Ваш демон cron не должен вызывать задания, если их предыдущие экземпляры все еще работают. Я разработчик одного cron daemon dcron , и мы специально пытаемся это предотвратить. Я не знаю, как Vixie cron или другие демоны справляются с этим.
источник
Я бы порекомендовал использовать команду run-one - намного проще, чем иметь дело с блокировками. Из документов:
run-one - это скрипт-обертка, который запускает не более одного уникального экземпляра некоторой команды с уникальным набором аргументов. Это часто полезно с cronjobs, когда вы хотите, чтобы одновременно работало не более одной копии.
run-this-one точно такой же, как и run-one, за исключением того, что он будет использовать pgrep и kill для поиска и уничтожения любых запущенных процессов, принадлежащих пользователю и соответствующих целевым командам и аргументам. Обратите внимание, что run-this-one будет блокироваться при попытке уничтожить соответствующие процессы, пока все соответствующие процессы не будут мертвыми.
run-one-постоянно работает точно так же, как run-one, за исключением того, что он вызывает «COMMAND [ARGS]» каждый раз, когда выходит из команды COMMAND (ноль или не ноль).
keep-one-running - это псевдоним для run-one-постоянно.
run-one-till-success работает точно так же, как run-one-постоянно, за исключением того, что она вызывает «COMMAND [ARGS]» до тех пор, пока COMMAND не завершится успешно (то есть выйдет из нуля).
run-one-till-fail работает точно так же, как run-one-постоянно, за исключением того, что он вызывает «COMMAND [ARGS]» до тех пор, пока COMMAND не завершится с ошибкой (то есть выйдет с ненулевым значением).
источник
Теперь, когда systemd отсутствует, в системах Linux есть еще один механизм планирования:
systemd.timer
В
/etc/systemd/system/myjob.service
или~/.config/systemd/user/myjob.service
:В
/etc/systemd/system/myjob.timer
или~/.config/systemd/user/myjob.timer
:Если сервисный блок уже активируется при следующем включении таймера, то другой экземпляр сервиса не будет запущен.
Альтернатива, которая запускает задание один раз при загрузке и через одну минуту после каждого запуска:
источник
Я создал одну банку, чтобы решить такую проблему, как если бы дублирующиеся кроны работали, это мог быть java или shell cron. Просто передайте имя cron в Duplicates.CloseSessions ("Demo.jar"), это будет искать и убивать существующий pid для этого cron, кроме текущего. Я реализовал метод, чтобы сделать это. String proname = ManagementFactory.getRuntimeMXBean (). GetName (); String pid = proname.split ("@") [0]; System.out.println («Текущий PID:» + pid);
А затем убить строку killid снова командой shell
источник
Ответ @Philip Reynolds начнет выполнять код после того, как время ожидания 5 секунд все равно не получит блокировку. Кажется, что следующий Flock не работает, я изменил ответ @Philip Reynolds на
так что код никогда не будет выполнен одновременно. Вместо этого через 5 секунд ожидания процесс завершится с 1, если к тому времени он не получит блокировку.
источник