긴 크론 작업이 병렬로 실행되는 것을 막는 일반적인 솔루션?


27

crontab에서 스크립트 또는 응용 프로그램을 실행하고 두 번 실행되지 않도록하는 간단하고 일반적인 솔루션을 찾고 있습니다.

솔루션은 실행 된 명령과 독립적이어야합니다.

lock && (command ; unlock)다른 잠금이 있으면 잠금이 false를 반환하는 위치 와 같아야한다고 가정합니다 .

두 번째 부분은 오류를 반환하더라도 잠금, 실행 명령 및 명령 실행 후 잠금 해제를 얻은 경우와 같습니다.

답변:


33

상기 봐 가지고 실행 하나의런온 설치 패키지. 로부터 에 대한 맨 페이지 run-one명령맨 페이지 아이콘 :

run-one 은 고유 한 인수 세트를 사용하여 명령의 고유 인스턴스를 하나 이상 실행하는 랩퍼 스크립트입니다.

한 번에 하나 이상의 사본을 실행하지 않으려는 경우 cronjob에 유용합니다.

time또는 과 같이 sudo명령 앞에 추가하면됩니다. 따라서 cronjob은 다음과 같습니다.

  */60 * * * *   run-one rsync -azP $HOME example.com:/srv/backup

자세한 내용과 배경 은 Dustin Kirkland가 소개 한 블로그 게시물을 확인하십시오 .


5

잠금을 설정하는 매우 간단한 방법 :

if mkdir /var/lock/mylock; then
  echo "Locking succeeded" >&2
else
  echo "Lock failed - exit" >&2
  exit 1
fi

실행하려는 스크립트는 잠금을 생성해야합니다. 잠금이 존재하면 다른 스크립트가 사용 중이므로 첫 번째 스크립트를 실행할 수 없습니다. 파일이 존재하지 않으면 스크립트가 잠금을 획득하지 않은 것입니다. 따라서 현재 스크립트는 잠금을 획득합니다. 스크립트가 완료되면 잠금을 제거하여 잠금을 구현해야합니다.

bash 잠금에 대한 자세한 내용은 페이지를 확인 하십시오.


1
종료시 잠금을 제거하는 EXIT 트랩도 필요합니다. echo "Locking succeeded" >&2; trap 'rm -rf /var/lock/mylock' EXIT
geirha

1
하위 작업으로 원하는 명령을 실행하는 프로세스에서 권고 무리를 사용하는 것이 이상적입니다. 그렇게하면 모두 죽으면 무리가 자동으로 풀리므로 잠금 파일이 존재 하지 않습니다. 네트워크 포트를 사용하여 비슷한 방식으로 작동합니다 - 그는 비록 방법으로 문제가 작은 공간.
Alex North-Keys

3

멋진 패키지를 설치할 필요가 없습니다.

#!/bin/bash
pgrep -xf "$*" > /dev/null || "$@"

"apt-get install"을 실행하는 것보다 스크립트를 직접 작성하는 것이 더 빠르지 않습니까? 현재 사용자 만 실행하는 인스턴스를 확인하기 위해 "-u $ (id -u)"를 pgrep에 추가 할 수 있습니다.


2
단일 인스턴스를 보장하지는 않습니다. 두 스크립트는 ||동시에 스크립트를 시작할 수있는 기회를 갖기 전에 동시에 다른 운영자 에게 전달할 수 있습니다 .
Sedat Kapanoglu

@SedatKapanoglu 물론,이 스크립트는 경쟁 조건에 맞지 않지만 원래의 질문은 오랫동안 실행되는 크론 작업 (분당 최대 1 회 실행)에 관한 것이 었습니다. 프로세스 생성에 1 분 이상 시스템이 필요한 경우 다른 문제가 있습니다. 그러나 다른 이유로 필요한 경우 flock (1)을 사용하여 경쟁 조건으로부터 위의 스크립트를 보호 할 수 있습니다.
Michael Kowhan

나는 이것을 사용했지만 스스로 확인 해야하는 bash 스크립트에 사용했다. 코드는 다음과 같습니다. v = $ (pgrep -xf "/ bin / bash $ 0 $ @") [ "$ {v / $ BASHPID /}"! = ""] && exit 2
ahofmann

3

solo사용자에게 고유 한 루프백 주소의 포트를 바인딩하여 잠금을 수행하는 Tim Kay 's도 참조하십시오 .

http://timkay.com/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;

Mac OSX 의 경우 method의 세 번째 매개 변수 solo(3801): Can't assign requested address를 강제로 설정하지 않으면 오류와 함께 실패 합니다. BSD에 좋은 것은 Mac에도 좋습니다. 0pack
Eric Leschinski

1

자물쇠가 필요합니다. run-one작업을 수행하지만 패키지 flock에서 살펴볼 수도 있습니다 util-linux.

커널 개발자가 제공하는 표준 패키지로, 더 많은 사용자 정의를 허용하며 run-one여전히 매우 간단합니다.


0

나를 위해 일한 bash-hackers.org 의 간단한 솔루션은 mkdir 을 사용하는 것 입니다. 이것은 하나의 프로그램 인스턴스 만 실행되도록하는 쉬운 방법입니다. 있는 디렉토리 만들기 에서 mkdir .lock 하는 수익을

  • 성공적으로 만든 경우 true
  • 잠금 파일이 존재하면 현재 실행중인 인스턴스가 하나 있음을 나타내는 false 입니다.

따라서이 간단한 함수는 모든 파일 잠금 논리를 수행했습니다.

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

이 솔루션은 자체 확인이 필요한 bash 스크립트를위한 것입니다.

v=$(pgrep -xf "/bin/bash $0 $@")
[ "${v/$BASHPID/}" != "" ] && exit 0
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.