8

我打赌有人已经解决了这个问题,也许我使用了错误的谷歌搜索词来告诉我答案,但这是我的情况。

我有一个要运行的脚本,但我希望它只在预定时运行,并且一次只运行一个。(不能同时运行脚本)

现在棘手的部分是说我有一个名为“myhappyschedule”的表,其中包含我需要的数据和预定的时间。这张表甚至可以同时有多个预定时间,每个都运行这个脚本。所以基本上我需要一个每次脚本触发的队列,他们都需要等待每个脚本完成。(有时这可能只需要一分钟,脚本有时会执行很多分钟)

我正在考虑做的是制作一个脚本,每 5 分钟检查一次 myhappyschedule 并收集那些安排好的,将它们放入队列中,另一个脚本可以按顺序执行队列中的每个“作业”或事件。这一切听起来很混乱。

为了让它更长 - 我应该说我允许用户在 myhappyschedule 中安排事情而不是编辑 crontab。

关于这个还能做什么?文件锁和脚本调用脚本?

4

3 回答 3

4

添加一列exec_statusmyhappytable也许也time_startedtime_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 脚本被杀死,计划任务将保持在“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
于 2008-10-22T16:49:31.607 回答
2

您可以在脚本中使用 at(1) 命令来安排其下一次运行。在它退出之前,它可以检查 myhappyschedule 的下一次运行时间。你根本不需要cron,真的。

于 2008-10-22T16:15:54.420 回答
0

我在研究排队问题的解决方案时遇到了这个问题。为了其他在这里搜索的人的利益,这是我的解决方案。

将此与按计划启动作业的 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、、shabugabusingle_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
于 2009-05-07T20:49:38.980 回答