crontab 解決週期內未執行完重複執行

2021-07-16 03:25:24 字數 2693 閱讀 8053

linux 下的 crontab 定時任務服務,可以用來定時執行指令碼。工作中經常會用到這樣的服務,使用起來比較簡單。

/sbin/service crond start  # 開啟服務

/sbin/service crond stop # 停止服務

/sbin/service crond restart #重啟服務

sudo crontab -e #插入一條定時任務

sudo crontab -l #檢視所有的 root 使用者下的定時任務列表

tail -f /var/log/cron # 實時檢視定時任務日誌

#例如,新增如下一條定時任務

#分 時 日 月 周

* * * * * php test.php

最近在工作中經常會用到定時任務,發現當我們的腳步的執行時間(假設:130s)大於定時任務的設定時間(假設:1分鐘)時,定時任務會重複開始執行,即上次的任務還沒有執行完,下次的任務的又開始執行。往往執行的指令碼裡的資源是不允許同時兩個指令碼同時共享資源,即保證操作的原子性。這樣會造成執行出錯,下面我們來驗證一下。

以下是乙個測試的 php 指令碼,該指令碼執行一次需要 130s

<?php

$time = time();

$id = uniqid(); //一次執行的唯一標示

while(time() - $time

< 130)

然後新增定時任務,每分鐘(60s)執行一次

*/1 * * * * php /home/phachon/cron/test.php
過一段時間後,檢視日誌:

分析日誌我們會發現 id = 57bbcd4d10262 的任務在 12:13:01 開始,但是還沒有結束的時候,id=57bbcd890e7f7 和 id=57bbcdc510685 的任務就已經開始了,這樣明顯存在問題。我們想要的是每次單獨執行完後,下乙個執行開始:

利用臨時檔案

思路很簡單,在執行檔案的開頭先判斷是否有乙個 test.lock 的檔案,如果有 test.lock 檔案,則 exit(),如果沒有的話,建立 test.lock 檔案,然後執行指令碼檔案,執行完畢刪除 test.lock;

實現後**:

<?php

$time = time();

$id = uniqid();

$lock = '/home/phachon/cron/lock/test.lock';

if(file_exists($lock))

touch($lock);

while(time() - $time

< 130)

unlink($lock);

檢視日誌如下:

利用指令碼加鎖

思路和第一種方式類似,只是不是用檔案判斷的方式,而是給檔案加鎖的方式

實現**:

<?php

$fp = fopen("/tmp/lock.txt", "w+");

// 進行排它型鎖定

if (flock($fp, lock_ex | lock_nb)) else

fclose($fp);

?>

第一種和第二種方法本質思路一樣,確實也解決了問題,但是這樣需要加**在我們的指令碼裡,而且,這樣其實 crontab 服務還是多了很多不必要的執行,浪費資源。

我們需要找到更加好的方法,在執行**前就已經判斷是否可以執行指令碼。

利用 linux flock 鎖機制

利用 flock(freebsd lockf,centos下為 flock),在指令碼執行前先檢測能否獲取某個檔案鎖,以防止指令碼執行衝突。

格式:

flock [-sxun][-w #] fd#

flock [-sxon][-w #] file [-c] command

選項:

-s, --shared:    獲得乙個共享鎖 

-x, --exclusive: 獲得乙個獨佔鎖

-u, --unlock: 移除乙個鎖,指令碼執行完會自動丟棄鎖

-n, --nonblock: 如果沒有立即獲得鎖,直接失敗而不是等待

-w, --timeout: 如果沒有立即獲得鎖,等待指定時間

-o, --close: 在執行命令前關閉檔案的描述符號。用於如果命令產生子程序時會不受鎖的管控

-c, --command: 在shell中執行乙個單獨的命令

-h, --help 顯示幫助

-v, --version: 顯示版本

鎖型別:

共享鎖:多個程序可以使用同一把鎖,常被用作讀共享鎖

獨佔鎖:同時只允許乙個程序使用,又稱排他鎖,寫鎖。

這裡我們需要同時只允許乙個程序使用,所以使用獨佔鎖。

修改後的定時任務如下:

*/1 * * * *  flock -xn /tmp/test.lock -c 'php /home/phachon/cron/test.php' >> /home/phachon/cron/cron.log'
日誌如下:

完美的解決了我們的問題

總體看來,還是用第三種方法比較好,而且也方便.

crontab防止指令碼週期內未執行完重複執行

八月 28,2015 no comments 個人體會 flock xn my.lock commond my.lock是乙個檔案,應該可以是任意檔案,可以新建乙個空檔案 當flock 獲得鎖後就會執行後面的 commond 測試過程 1 flock xn my.lock sleep 20 2 fl...

crontab任務未執行

最近在ubuntu系統中使用crontab定時任務遇到了問題,現記錄下來,希望能夠幫助到遇到同樣問題的同學。問題描述 使用crontab做mysql資料庫的定時備份,發現到點确沒有正常執行任務完成備份操作。解決思路 1.使用 service cron status 檢視crontab任務是否正常啟動...

unix週期執行指令Crontab命令

鏈結 主要內容 簡單解釋一下 crontab e 編輯,類似 vim,儲存退出時會檢查語法 l 列舉所有任務 r 刪除所有任務 如果 crontab 執行出錯,可以檢視日誌檔案 var log syslog 基本語法 min表示分鐘,範圍 0 59 hour表示小時,範圍 0 23 day表示天,範...