Я ищу простое и универсальное решение, которое позволило бы вам выполнить любой скрипт или приложение в crontab и предотвратить его запуск дважды.
Решение должно быть независимым от выполненной команды.
Я предполагаю, что это должно выглядеть как lock && (command ; unlock)
, где lock вернет false, если была другая блокировка.
Вторая часть была бы похожа на получение блокировки, запуска команды и разблокировки после выполнения команды, даже если она возвращает ошибку.
Взгляните на пакет run-one
. Из справочной страницы для команды run-one
:
run-one - это сценарий оболочки, который запускает не более одного уникального экземпляр некоторой команды с уникальным набором аргументов.
Это часто бывает полезно с cronjobs, когда вы хотите, чтобы одновременно выполнялось не более одной копии.
Например, time
или sudo
, просто добавьте его к команде. Таким образом, cronjob может выглядеть так:
*/60 * * * * run-one rsync -azP $HOME example.com:/srv/backup
Для получения дополнительной информации и предыстории ознакомьтесь с сообщением в блоге, представляющим его Дастином Киркландом.
Это решение для сценарий bash, который должен проверять себя
v=$(pgrep -xf "/bin/bash $0 $@")
[ "${v/$BASHPID/}" != "" ] && exit 0
Простым решением из bash-hackers.org, которое работало на меня, было использование mkdir. Это простой способ убедиться, что запущен только один экземпляр вашей программы. Создайте каталог с mkdir .lock, который возвращает
if mkdir .lock; then
echo "Locking succeeded"
eval startYourProgram.sh ;
else
echo "Lock file exists. Program already running? Exit. "
exit 1
fi
echo "Program finished, Removing lock."
rm -r .lock
Вам нужна блокировка. run-one
выполняет свою работу, но вы также можете изучить flock
из пакета util-linux
.
Это стандартный пакет, предоставляемый разработчиками ядра, допускает больше настроек, чем run-one
, и по-прежнему очень прост.
См. Также solo
Тима Кея, который выполняет блокировку путем привязки порта к адресу обратной связи, уникальному для пользователя:
В случае отказа его сайта:
Использование:
solo -port=PORT COMMAND
where
PORT some arbitrary port number to be used for locking
COMMAND shell command to run
options
-verbose be verbose
-silent be silent
Используйте его так:
* * * * * solo -port=3801 ./job.pl blah blah
Скрипт:
#!/usr/bin/perl -s
#
# solo v1.7
# Prevents multiple cron instances from running simultaneously.
#
# Copyright 2007-2016 Timothy Kay
# http://timkay.com/solo/
#
# It is free software; you can redistribute it and/or modify it under the terms of either:
#
# a) the GNU General Public License as published by the Free Software Foundation;
# either version 1 (http://dev.perl.org/licenses/gpl1.html), or (at your option)
# any later version (http://www.fsf.org/licenses/licenses.html#GNUGPL), or
#
# b) the "Artistic License" (http://dev.perl.org/licenses/artistic.html), or
#
# c) the MIT License (http://opensource.org/licenses/MIT)
#
use Socket;
alarm $timeout if $timeout;
$port =~ /^\d+$/ or $noport or die "Usage: $0 -port=PORT COMMAND\n";
if ($port)
{
# To work with OpenBSD: change to
# $addr = pack(CnC, 127, 0, 1);
# but make sure to use different ports across different users.
# (Thanks to www.gotati.com .)
$addr = pack(CnC, 127, $<, 1);
print "solo: bind ", join(".", unpack(C4, $addr)), ":$port\n" if $verbose;
$^F = 10; # unset close-on-exec
socket(SOLO, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!";
bind(SOLO, sockaddr_in($port, $addr)) or $silent? exit: die "solo($port): $!\n";
}
sleep $sleep if $sleep;
exec @ARGV;
Не нужно устанавливать какой-то необычный пакет:
#!/bin/bash
pgrep -xf "$*" > /dev/null || "$@"
Быстрее написать этот сценарий самостоятельно, чем запускать "apt-get install", не так ли? Вы можете добавить "-u $ (id -u)" к pgrep, чтобы проверять экземпляры, запущенные только текущим пользователем.
Очень простой способ установки блокировки:
if mkdir /var/lock/mylock; then
echo "Locking succeeded" >&2
else
echo "Lock failed - exit" >&2
exit 1
fi
Сценарии, которые хотят запустить, должны создать блокировку. Если блокировка существует, другой сценарий занят, поэтому первый сценарий не может работать. Если файл не существует, никакой сценарий не получил блокировку. Таким образом, текущий сценарий получает блокировку. Когда сценарий завершит работу, необходимо снять блокировку, сняв блокировку.
Для получения дополнительных сведений о блокировках bash посетите эту страницу