2008-10-22 67 views
8

我敢打賭,有人已經解決了這個問題,也許我使用谷歌的錯誤搜索條件告訴我答案,但這是我的情況。cron腳本充當隊列還是cron隊列?

我有一個腳本,我想運行,但我希望它只在計劃時運行,並且一次只運行一個腳本。 (不能同時運行腳本)

現在的粘性部分是說我有一個名爲「myhappyschedule」的表,它具有我需要的數據和預定的時間。此表可以有多個計劃時間,即使在同一時間,每個人都可以運行此腳本。所以基本上我需要每次腳本觸發時都有一個隊列,並且在它完成之前它們都需要等待每個腳本。 (有時這可能需要一分鐘的時間,腳本有時會執行很多分鐘)

我想要做的是製作一個腳本,每5分鐘檢查一下myhappyschedule並收集那些計劃好的,將它們進入另一個腳本可以按順序執行每個「作業」或隊列中的發生的隊列。這聽起來很亂。

爲了讓這個更長 - 我應該說我允許用戶在myhappyschedule中安排事情,而不是編輯crontab。

你認爲如何能這樣做嗎?文件鎖定和腳本調用腳本?

回答

3

添加一列exec_status到(也許還time_startedtime_finished,看到僞代碼)

運行下面的cron腳本每隔x分鐘的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腳本被殺死,計劃的任務將保持「執行_」狀態。這就是開始和結束時的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 
2

您可以在腳本中使用at(1)命令來安排其下一次運行。在退出之前,它可以檢查我的下一次運行時間。真的,你根本不需要cron。

+0

好吧..這是我沒有想到的。我想知道腳本運行時預定的時間是否可以通過。假設它在上午8:00執行,並且腳本運行10分鐘,並且在運行開始和結束時間之間的任何時間都會丟失。 – user30413 2008-10-22 16:49:00

+0

好點。您可能希望在編輯myhappyschedule的任何過程中操作atq。午餐時我必須考慮這個問題。 – 2008-10-22 17:07:25

0

我在研究排隊問題的解決方案時遇到了這個問題。爲了在這裏搜索的任何人的利益是我的解決方案。

將此功能與按計劃啓動作業的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 

的腳本創建爲每個命令一個新named pipe。所以上面將創建命名管道:sleepshabugabusingle_instance_script

在這種情況下,最初的通話將開始一個閱讀器,並與some arguments作爲參數運行single_instance_script。一旦調用完成,讀者會搶掉管道中的下一個請求,並與some other_arguments執行,完成,搶下等等

這個腳本會阻塞請求進程,以便把它作爲後臺作業(&在結束)或帶atat 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