web-dev-qa-db-fra.com

Solution générique pour empêcher un travail cron long de s'exécuter en parallèle?

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.

27
sorin

Jetez un oeil à la run-one Install run-one package. Depuis la page de manuel pour la commande run-one Manpage icon :

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.

33
andrewsomething

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

5
OrangeTux

Voir aussi solode Tim Kay, qui effectue le verrouillage en liant un port à une adresse de bouclage unique pour l'utilisateur:

http://timkay.com/solo/

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;
3
DNA

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.

3
Michael Kowhan

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.

1
styrofoam fly

Cette solution est pour un script bash qui doit se vérifier

v=$(pgrep -xf "/bin/bash $0 $@")
[ "${v/$BASHPID/}" != "" ] && exit 0
0
ahofmann

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

  • true si la création a réussi et
  • false si le fichier de verrouillage existe, ce qui indique qu'une instance est en cours d'exécution.

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
0
domih