2008-10-22 6 views
8

나는 누군가가 이미이 문제를 해결했으며 아마 Google에 잘못된 검색어를 사용하여 답변을 알려주고 있다고 확신하지만 여기에는 내 상황이 있습니다.cron 스크립트가 대기열 또는 cron 대기열 역할을합니까?

스크립트를 실행하고 싶지만 일정이 잡혀 있고 한 번에 하나씩 만 실행되도록하고 싶습니다. (스크립트를 동시에 실행할 수 없음)

이제 끈적 부분은 필자가 필요로하는 데이터와 예정된 시간을 가진 "myhappyschedule"이라는 테이블이 있다고합니다. 이 테이블은 동시에 여러 예약 된 시간을 가질 수 있으며, 각각은이 스크립트를 실행합니다. 그래서 본질적으로 스크립트가 실행될 때마다 대기열이 필요하며, 모두 끝내기 전에 각각 기다려야합니다. (때로는 스크립트가 때로는 많은 시간 (분)을 실행하는 데 단지 1 분이 걸릴 수도 있습니다)

제가 생각하는 것은 매 5 분마다 myhappyschedule을 검사하고 예약 된 것을 수집하고 스크립트를 작성하는 것입니다 다른 스크립트가 큐의 각 '작업'또는 발생을 순서대로 실행할 수있는 큐에 넣습니다. 어느 것이 지저분하게 들리는 지.

더 길게하려면 사용자가 myhappyschedule 일정을 수락하고 crontab을 편집하지 못하게해야한다고 말해야합니다.

이 작업에 대해 수행 할 수있는 작업은 무엇입니까? 스크립트를 호출하는 파일 잠금 및 스크립트?

답변

3

(의사 코드를 참조 어쩌면 또한 time_startedtime_finished) exec_statusmyhappytable에 열

은 다음과 크론 스크립트마다 X 분 크론 스크립트의

의사를 실행에 추가 스크립트는 먼저 실행중인 명령이 없는지 확인한 다음 지정된 시점에 실행할 명령이 없을 때까지 실행되지 않은 첫 번째 명령을 실행합니다. 또한 데이터베이스를 조회하여 실행중인 명령을 볼 수 있습니다.

잠재적 인 함정 : cron 스크립트가 종료되면 예약 된 작업은 "execution_now"상태로 유지됩니다. 이것이 시작과 끝 부분의 pid lock은 cron 스크립트가 제대로 종료되었는지 확인하는 것입니다. 생성/검사 피들 블록의 의사 코드 :

if exists pidlockfile then 
    check if process id given in file exists 
    if not exists then 
    update myhappytable set exec_status = error_cronscript_died_while_executing_this 
     where exec_status == executing_now 
    delete pidlockfile 
    else (previous instance still running) 
    exit 
    endif 
endif 
create pidlockfile containing cron script process id 
+0

이것은 의사 큐 (pseudo-code)로 작업 대기열과 관련하여 나쁘게 지원되지 않는 경로로 향하게되었습니다. Piskvor에게 감사드립니다. – bouvard

2

스크립트 내에서 at (1) 명령을 사용하여 다음 실행을 예약 할 수 있습니다. 종료하기 전에 다음 실행 시간에 대한 myhappyschedule을 확인할 수 있습니다. 정말로 cron은 필요 없습니다.

[create/check pid lock (optional, but see "A potential pitfall" below)] 
get number of rows from myhappytable where (exec_status == executing_now) 
if it is > 0, exit 
begin loop 
    get one row from myhappytable 
    where (exec_status == not_yet_run) and (scheduled_time <= now) 
    order by scheduled_time asc 
    if no such row, exit 
    set row exec_status to executing_now (maybe set time_started to now) 
    execute whatever command the row contains 
    set row exec_status to completed 
    (maybe also store the command output/return as well, set time_finished to now) 
end loop 
[delete pid lock file (complementary to the starting pid lock check)] 

이 방법 :

+0

글쎄 .. 그게 내가 생각하지 않은 일이었다. 스크립트가 실행되는 동안 예약 된 시간이 지나갈 지 궁금합니다. 오전 8시에 실행되고 스크립트가 10 분 동안 실행되고 시작 및 종료 시간 사이에 예약 된 시간을 놓친 경우 – user30413

+0

좋은 지적. myhappyschedule을 편집하는 모든 프로세스에서 atq를 조작하고자 할 수 있습니다. 점심을 먹고 생각해 봐야 겠어. –

+0

나는 스크립트가 실행이 끝날 때 myhappyschedule을 검사하고 myhappyschedule 중 가장 빠른 스케줄 된 시작 시간을 선택하여 런타임에 다음 시간을 알아 내면 의도 한대로 작동한다고 생각한다. 열쇠는 myhappyschedule에서 가장 빠른 시간입니다. –

0

큐잉 문제에 대한 해결책을 연구하는 동안이 질문이 나타났습니다. 여기에서 찾는 다른 사람의 이익을 위해 나의 해결책입니다.

작업을 예약 할 때 (동시에 실행되도록 예약 된 경우에도) 작업을 시작하고 설명한 문제를 해결하는 cron과 결합하십시오.

스크립트의 대부분의 인스턴스에서


  • 문제가 실행되어야한다.
  • Google은 가능한 한 빨리 처리 요청을 요청하고 싶습니다.

즉. 우리는 스크립트에 파이프 라인이 필요합니다.

솔루션 :


는 모든 스크립트에 파이프 라인을 만듭니다. 작은 bash 스크립트 (더 아래로)를 사용하여 완료.

스크립트


./pipeline "<any command and arguments go here>"

예로 호출 할 수 있습니다

./pipeline sleep 10 & 
./pipeline shabugabu & 
./pipeline single_instance_script some arguments & 
./pipeline single_instance_script some other_argumnts & 
./pipeline "single_instance_script some yet_other_arguments > output.txt" & 
..etc 

스크립트는 각 명령에 대한 새로운 named pipe을 만듭니다. 따라서 위에 언급 만들 것이다 파이프 : sleep, shabugabusingle_instance_script

초기 호출이 독자를 시작하고 인수로 some argumentssingle_instance_script를 실행합니다이 경우. 호출이 완료되면, 독자는 등 ... 다음을 잡아 완료, 파이프 오프 다음 요청을 잡고 some other_arguments으로 실행됩니다

상기 (배경 작업으로 &를 호출 그래서 프로세스를 요청 차단이 스크립트 끝) 또는) at (at now <<< "./pipeline some_script"와 분리 된 프로세스로

#!/bin/bash -Eue 

# Using command name as the pipeline name 
pipeline=$(basename $(expr "$1" : '\(^[^[:space:]]*\)')).pipe 
is_reader=false 

function _pipeline_cleanup { 
     if $is_reader; then 
       rm -f $pipeline 
     fi 
     rm -f $pipeline.lock 

     exit 
} 
trap _pipeline_cleanup INT TERM EXIT 

# Dispatch/initialization section, critical 
lockfile $pipeline.lock 
     if [[ -p $pipeline ]] 
     then 
       echo "$*" > $pipeline 
       exit 
     fi 

     is_reader=true 
     mkfifo $pipeline 
     echo "$*" > $pipeline & 
rm -f $pipeline.lock 

# Reader section 
while read command < $pipeline 
do 
     echo "$(date) - Executing $command" 
     ($command) &> /dev/null 
done