题
我敢打赌有人已经解决了这个问题,也许我使用了错误的谷歌搜索词来告诉我答案,但这是我的情况。
我有一个想要运行的脚本,但我希望它仅在计划时运行,并且一次只能运行一个。(不能同时运行脚本)
现在最棘手的部分是,假设我有一个名为“myhappyschedule”的表,其中包含我需要的数据和预定时间。该表可以有多个计划时间,甚至在同一时间,每个时间都会运行该脚本。因此,本质上,每次脚本触发时我都需要一个队列,并且它们都需要等待每个脚本完成之前。(有时脚本执行可能只需要一分钟,有时需要很多很多分钟)
我正在考虑做的是制作一个脚本,每 5 分钟检查一次 myhappyschedule 并收集那些已安排的内容,将它们放入队列中,另一个脚本可以按顺序执行队列中的每个“作业”或事件。这一切听起来都很混乱。
为了延长这个时间 - 我应该说我允许用户在 myhappyschedule 中安排事情而不是编辑 crontab。
关于这个还能做什么?文件锁和脚本调用脚本?
解决方案
将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)]
这样,脚本首先检查是否所有命令都在运行,然后先运行not-yet run命令,直到在给定时刻没有其他命令运行。此外,您可以通过查询数据库来查看正在执行的命令。
潜在的陷阱:如果cron脚本被杀死,则计划任务将保留在<!>“execution_now <!>”中;州。这就是开始和结束时的pid锁定:查看cron脚本是否正确终止。 create / check 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 结合起来(即使它们计划同时运行),也可以解决您所描述的问题。
问题
- 该脚本最多应运行一个实例。
- 我们希望提示请求以尽快处理它们。
IE。我们需要一个通往脚本的管道。
解决方案:
创建任何脚本的管道。使用一个小的 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