중복 크론 작업 실행 방지


92

나는 매분마다 cron 작업을 실행하도록 예약했지만 때로는 스크립트를 완료하는 데 1 분 이상이 걸리며 작업이 서로 "스태킹"되기를 원하지 않습니다. 나는 이것이 동시성 문제라고 생각합니다. 즉, 스크립트 실행은 상호 배타적이어야합니다.

이 문제를 해결하기 위해 스크립트에서 특정 파일 ( " lockfile.txt ") touch이 있는지 찾아보고없는 경우 종료합니다 . 그러나 이것은 꽤 거친 세마포입니다! 알아야 할 모범 사례가 있습니까? 대신 데몬을 작성 했어야합니까?

답변:


118

이 기능을 자동화하고 성가신 버그와 잠재적 버그를 직접 해결하고 뒤에서 무리를 사용하여 부실 잠금 문제를 피하는 몇 가지 프로그램이 있습니다 (터치 만 사용하면 위험합니다) . 내가 사용했습니다 lockrunlckdo과거에,하지만 지금은 거기에 flock대단한 (폴더의 유틸리티 - 리눅스의 약간 새로운 버전에서) (1). 사용하기 정말 쉽습니다 :

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job

2
lckdo는 moreutils에서 제거 될 예정입니다. 이제 flock (1)이 util-linux에 있습니다. 그리고이 패키지는 기본적으로 Linux 시스템에서 필수이므로 패키지의 존재 여부에 의존 할 수 있어야합니다. 사용법은 아래를 참조하십시오.
jldugger

그래, 무리는 이제 내가 선호하는 옵션입니다. 답에 맞게 답변을 업데이트하겠습니다.
womble

누구 flock -n file command와 의 차이점을 알고 flock -n file -c command있습니까?
Nanne

2
@ Nanne, 코드를 확인해야하지만 교육받은 추측은 -c쉘을 통해 지정된 명령을 실행하는 것입니다 (맨 페이지 당) "bare"(non- -c) 형식은 exec주어진 명령입니다. . 쉘을 통해 무언가를 넣으면 쉘과 같은 일 (예 : ;또는로 분리 된 여러 명령 실행)을 수행 할 수 &&있지만 신뢰할 수없는 입력을 사용하는 경우 쉘 확장 공격을받을 수 있습니다.
womble

1
frequent_cron_job매 순간 실행되고 있음을 보여주기 위해 (가설 적) 명령 에 대한 주장 이었습니다. 나는 유용한 것을 추가하지 않았기 때문에 그것을 제거했으며 혼란을 일으켰습니다.
womble

28

쉘에서 가장 좋은 방법은 flock (1) 을 사용하는 것입니다

(
  flock -x -w 5 99
  ## Do your stuff here
) 99>/path/to/my.lock

1
fd 리디렉션의 까다로운 사용을지지 할 수 없습니다. 너무 환상적입니다.
womble

1
배쉬 또는 zsh을 나를 위해 구문 분석하지 않습니다 사이의 공간을 제거하기 위해 필요 99하고 >그래서입니다99> /...
카일 브랜

2
@ 하비에르 : 까다 롭고 비열한 것이 아니라 문서화 되고 까다 롭고 비열한 것 입니다.
womble

1
이것이 실행되는 동안 다시 시작하거나 프로세스가 어떻게 든 종료되면 어떻게됩니까? 그때 영원히 잠길까요?
Alex R

5
나는이 구조가 독점 잠금을 생성하지만 이것이 달성되는 방법의 메커니즘을 이해하지 못한다는 것을 이해합니다. 이 답변에서 '99'의 기능은 무엇입니까? 누구든지 이것을 설명해 주시겠습니까? 감사!
Asciiom

22

실제로 * flock -n대신에 사용될 수 있으므로 lckdo커널 개발자의 코드를 사용하게됩니다.

womble의 예제기반으로 다음과 같이 작성할 수 있습니다.

* * * * * flock -n /some/lockfile command_to_run_every_minute

BTW, 모두의 코드를 찾고 flock, lockrun그리고 lckdo똑같은 일을, 그래서 가장 쉽게 사용할 수 당신에게 어떤의 문제입니다.


2

잠금 파일을 사용할 수 있습니다. 스크립트가 시작되면이 파일을 작성하고 완료되면 삭제하십시오. 스크립트는 기본 루틴을 실행하기 전에 잠금 파일이 존재하는지 확인하고 그에 따라 진행해야합니다.

잠금 파일은 initscript와 Unix 시스템의 다른 많은 응용 프로그램 및 유틸리티에서 사용됩니다.


1
이것이 제가 개인적으로 구현 한 것을 본 유일한 방법입니다. 나는 OSS 프로젝트를위한 거울로 테이너의 제안에 따라에 사용
워렌

2

이전 실행이 완료 될 때까지 스크립트가 대기하도록하려면 지정하지 않았습니다. "작업이 서로"스태킹 "되기를 원하지 않기 때문에"이미 실행중인 경우 스크립트를 종료하고 싶다고 암시하는 것 같습니다.

따라서 lckdo 또는 이와 유사한 것에 의존하고 싶다면 다음과 같이하십시오.


PIDFILE=/tmp/`basename $0`.pid

if [ -f $PIDFILE ]; then
  if ps -p `cat $PIDFILE` > /dev/null 2>&1; then
      echo "$0 already running!"
      exit
  fi
fi
echo $$ > $PIDFILE

trap 'rm -f "$PIDFILE" >/dev/null 2>&1' EXIT HUP KILL INT QUIT TERM

# do the work


고맙습니다 귀하의 예가 도움이됩니다-이미 실행중인 경우 스크립트를 종료하고 싶습니다. ickdo 를 언급 주셔서 감사합니다 . 트릭을 수행하는 것 같습니다.
Tom

FWIW : 스크립트에 포함될 수 있기 때문에이 솔루션이 마음에 들기 때문에 스크립트 호출 방식에 관계없이 잠금이 작동합니다.
David G

1

이것은 또한 잘못된 일을하고 있다는 신호 일 수 있습니다. 작업이 밀접하고 자주 실행되는 경우 작업을 제거하고 데몬 스타일의 프로그램으로 만들어야합니다.


3
나는 이것에 진심으로 동의하지 않습니다. 주기적으로 실행해야 할 것이 있으면 데몬으로 만드는 것이 "너트를위한 망치"솔루션입니다. 사고를 예방하기 위해 잠금 파일을 사용하는 것은 결코 문제가 없었습니다.
womble

@womble 동의합니다; 그러나 나는 망치로 견과류를 부수는 것을 좋아합니다! :-)
wzzrd

1

cron 데몬은 이전 인스턴스가 여전히 실행중인 경우 작업을 호출하지 않아야합니다. 나는 하나의 cron 데몬 dcron 의 개발자이며 , 우리는 특히 그것을 막으려 고 노력합니다. Vixie cron 또는 다른 데몬이 이것을 어떻게 처리하는지 모르겠습니다.


1

잠금을 처리하는 것보다 훨씬 간단한 run-one 명령을 사용 하는 것이 좋습니다 . 문서에서 :

run-one 은 고유 한 인수 세트를 사용하여 명령의 고유 인스턴스를 하나 이상 실행하는 랩퍼 스크립트입니다. 한 번에 하나 이상의 사본을 실행하지 않으려는 경우 cronjob에 유용합니다.

run-this-one 은 pgrep 및 kill을 사용하여 사용자가 소유하고 실행중인 프로세스를 찾아서 대상 명령 및 인수와 일치시키는 것을 제외하고는 run-one과 정확히 같습니다. run-this-one은 일치하는 프로세스를 종료하려고 시도하는 동안 모든 일치하는 프로세스가 종료 될 때까지 차단됩니다.

RUN-one 은 COMMAND가 종료 될 때마다 (0 또는 0이 아닌) "COMMAND [ARGS]"를 다시 생성한다는 점을 제외하고는 run-one과 정확히 동일 하게 작동합니다.

keep-one-running한 번에 계속 실행 되는 별칭입니다.

명령이 성공적으로 종료 될 때까지 (즉, 0이 종료 될 때까지 "COMMAND [ARGS]"를 다시 생성한다는 점을 제외하고는 run-one-until-success 가 run-one-constantly처럼 정확하게 작동합니다.

실패시 실행 (즉, 0이 아닌 종료) 될 때까지 "COMMAND [ARGS]"를 다시 생성한다는 점을 제외하고는 run-one-until-failure 는 run-one-constantly와 정확히 동일하게 작동합니다.


1

systemd가 나오면 Linux 시스템에는 또 다른 스케줄링 메커니즘이 있습니다.

에이 systemd.timer

에서 /etc/systemd/system/myjob.service또는 ~/.config/systemd/user/myjob.service:

[Service]
ExecStart=/usr/local/bin/myjob

에서 /etc/systemd/system/myjob.timer또는 ~/.config/systemd/user/myjob.timer:

[Timer]
OnCalendar=minutely

[Install]
WantedBy=timers.target

다음에 타이머가 활성화 될 때 서비스 유닛이 이미 활성화 된 경우 서비스의 다른 인스턴스 가 시작 되지 않습니다 .

대안은 부팅시 한 번, 각 실행이 완료된 후 1 분 후에 작업을 시작합니다.

[Timer]
OnBootSec=1m
OnUnitInactiveSec=1m 

[Install]
WantedBy=timers.target

0

중복 크론이 실행되는 것과 같은 문제를 해결하기 위해 하나의 항아리를 만들었습니다 .Java 또는 쉘 크론 일 수 있습니다. Duplicates.CloseSessions ( "Demo.jar")에 cron 이름을 전달하면 현재를 제외하고이 cron에 대해 존재하는 pid를 검색하고 종료합니다. 이 작업을 수행하는 방법을 구현했습니다. String proname = ManagementFactory.getRuntimeMXBean (). getName (); 문자열 pid = proname.split ( "@") [0]; System.out.println ( "현재 PID :"+ pid);

            Process proc = Runtime.getRuntime().exec(new String[]{"bash","-c"," ps aux | grep "+cronname+" | awk '{print $2}' "});

            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String s = null;
            String killid="";

            while ((s = stdInput.readLine()) != null ) {                                        
                if(s.equals(pid)==false)
                {
                    killid=killid+s+" ";    
                }
            }

그런 다음 다시 쉘 명령으로 killid 문자열을 죽입니다.


나는 이것이 실제로 질문에 대답한다고 생각하지 않습니다.
kasperd

0

@Philip Reynolds 답변은 잠금을 얻지 않고 5 초 대기 시간 후에 코드 실행을 시작합니다. 다음 Flock이 작동하지 않는 것 같습니다. @Philip Reynolds의 답변을

(
  flock -w 5 -x 99 || exit 1
  ## Do your stuff here
) 99>/path/to/my.lock

코드가 동시에 실행되지 않도록합니다. 대신 5 초 대기 후 프로세스는 잠금을 얻지 못하면 1로 종료됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.