Je recherche une solution simple et générique qui vous permettrait d’exécuter n’importe quel script ou application dans crontab et de l’empêcher de s’exécuter deux fois.
La solution doit être indépendante de la commande exécutée.
Je suppose que cela devrait ressembler à lock && (command ; unlock)
où lock retournera false s'il y avait un autre verrou.
La deuxième partie serait comme si elle obtenait la commande lock, run, et unlock après que la commande soit exécutée, même si elle renvoyait une erreur.
Jetez un oeil à la run-one package. Depuis la page de manuel pour la commande run-one
:
run-one est un script wrapper qui n'exécute pas plus d'une instance unique d'une commande avec un ensemble unique d'arguments.
Ceci est souvent utile avec les tâches cron, lorsque vous ne voulez pas exécuter plus d’une copie à la fois.
Comme time
ou Sudo
, il vous suffit de l'ajouter à la commande. Ainsi, un travail cron pourrait ressembler à:
*/60 * * * * run-one rsync -azP $HOME example.com:/srv/backup
Pour plus d'informations et d'informations, consultez l'article de blog le présentant par Dustin Kirkland.
Un moyen très simple de configurer une serrure:
if mkdir /var/lock/mylock; then
echo "Locking succeeded" >&2
else
echo "Lock failed - exit" >&2
exit 1
fi
Un script qui veut être exécuté doit créer le verrou. Si le verrou existe, un autre script est occupé et le premier script ne peut donc pas être exécuté. Si le fichier n'existe pas, aucun script n'a acquis le verrou. Donc, le script actuel acquiert le verrou. Lorsque le script est terminé, le verrouillage doit être libéré en le retirant.
Pour plus d'informations sur les verrous bash, consultez la section this page
Voir aussi solo
de Tim Kay, qui effectue le verrouillage en liant un port à une adresse de bouclage unique pour l'utilisateur:
En cas de panne de son site:
Usage:
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
Utilisez-le comme ceci:
* * * * * solo -port=3801 ./job.pl blah blah
Scénario:
#!/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;
Pas besoin d'installer un paquet de fantaisie:
#!/bin/bash
pgrep -xf "$*" > /dev/null || "$@"
Il est plus rapide d'écrire ce script vous-même que de lancer "apt-get install", n'est-ce pas? Vous voudrez peut-être ajouter "-u $ (id -u)" au pgrep pour vérifier les instances exécutées uniquement par l'utilisateur actuel.
Vous avez besoin d'un verrou. run-one
fait le travail, mais vous voudrez peut-être aussi examiner le nom flock
du paquetage util-linux
.
C’est un paquet standard fourni par les développeurs du noyau, qui permet plus de personnalisation que run-one
et qui reste très simple.
Cette solution est pour un script bash qui doit se vérifier
v=$(pgrep -xf "/bin/bash $0 $@")
[ "${v/$BASHPID/}" != "" ] && exit 0
Une solution simple de bash-hackers.org qui a fonctionné pour moi utilisait mkdir . C’est un moyen simple de s’assurer qu’une seule instance de votre programme est en cours d’exécution. Créez un répertoire avec mkdir .lock qui renvoie
Donc, cette fonction simple a fait toute la logique de verrouillage de fichier:
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