CRON 스크립트 CRON의 대기열 또는 대기열 역할을하는 CRON 스크립트?
문제
나는 누군가가 이미 이것을 해결했다고 베팅하고있을 것입니다. 아마도 Google에 대한 잘못된 검색어를 사용하여 답을 알려주는데 여기에 내 상황이 있습니다.
실행하고 싶은 스크립트가 있지만 예약 할 때만 실행하고 한 번에만 실행하기를 원합니다. (스크립트를 동시에 실행할 수 없습니다)
이제 끈적 끈적한 부분은 내가 필요한 데이터와 예정된 시간을 가진 "myhappyschedule"이라는 테이블이 있다는 것입니다. 이 테이블은 동시에 여러 예약 시간을 가질 수 있으며 각 테이블은이 스크립트를 실행합니다. 따라서 본질적으로 스크립트가 발사 될 때마다 대기열이 필요하며마다 끝날 때까지 각각을 기다려야합니다. (때로는 스크립트가 때때로 몇 분 동안 실행하는 데 1 분이 걸릴 수 있습니다)
내가 생각하는 것은 5 분마다 myhappyschedule을 점검하고 예정된 것을 수집하는 스크립트를 만드는 것입니다. 다른 스크립트가 각 '작업'을 실행하거나 대기열에서 발생할 수있는 대기열에 넣습니다. 이 모든 것이 지저분하게 들립니다.
이것을 더 길게 만들기 위해 - 나는 사용자가 crontab을 편집하지 않고 myhappyschedule에서 예약 할 수 있도록 허용한다고 말해야합니다.
이것에 대해 무엇을 할 수 있습니까? 스크립트를 호출하는 파일 잠금 및 스크립트?
해결책
열을 추가하십시오 exec_status
에게 myhappytable
(아마도 time_started
그리고 time_finished
, 의사 코드 참조)
X 분마다 다음 CRON 스크립트를 실행하십시오
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)]
이런 식으로 스크립트는 먼저 명령이 실행되지 않는지 확인한 다음 주어진 순간에 더 이상 명령을 실행할 때까지 먼저 실행되지 않은 명령을 실행합니다. 또한 데이터베이스를 쿼리하여 어떤 명령이 실행되는지 확인할 수 있습니다.
잠재적 인 함정 : CRON 스크립트가 죽으면 예정된 작업은 "executing_now"상태로 유지됩니다. 그것이 시작과 끝에서의 PID 잠금 장치의 것입니다. CRON 스크립트가 제대로 종료되었는지 확인합니다. PIDLOCK 생성/점검의 의사 코드 :
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
다른 팁
스크립트 내부의 AT (1) 명령을 사용하여 다음 실행을 예약 할 수 있습니다. 종료되기 전에 다음 달리기 시간에 대해 MyHappySchedule을 확인할 수 있습니다. 당신은 정말로 Cron이 필요하지 않습니다.
나는 대기열 문제에 대한 해결책을 연구하는 동안이 질문을 발견했습니다. 다른 사람이 여기서 검색하는 이점은 내 해결책입니다.
이를 예약 할 때 작업을 시작하는 CRON과 결합하고 (동시에 실행할 예정이더라도) 설명 된 문제도 해결합니다.
문제
- 스크립트의 최대 한 인스턴스가 실행되어야합니다.
- 우리는 가능한 빨리 처리하기위한 요청을 큐를 원합니다.
즉. 스크립트에 파이프 라인이 필요합니다.
해결책:
모든 스크립트에 파이프 라인을 만듭니다. 작은 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
스크립트는 새로운 것을 만듭니다 명명 된 파이프 각 명령에 대해. 따라서 위는 이름이 지정된 파이프를 만듭니다. sleep
, shabugabu
, 그리고 single_instance_script
이 경우 초기 호출은 독자를 시작하고 실행됩니다. single_instance_script
~와 함께 some arguments
논쟁으로. 통화가 완료되면 독자는 다음 요청을 파이프에서 가져 와서 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