你一定是用了假的 Linux cron

rovast發表於2019-03-11

場景

好多系統中會用到郵件系統,我們假設有一個 PHP 指令碼用來傳送郵件。使用 Linux cron 每分鐘執行一次

我們暫時不引入佇列系統,其實使用佇列處理此方式更優。

我們得到下面的基本配置

* * * * * php /home/app/email.php

問題分析和解決

如果這個郵件服務出現異常,程式僵死怎麼辦?

假設由於未知因素, email.php 指令碼一直執行,沒有退出。極端的情況,進入一個 while 死迴圈。

這下倒好,原來說好的一分鐘執行一次,現在一直死這邊了,後面的指令碼也不能跑了


解決辦法:

使用 timeout,假設我們設定每個指令碼最多執行時間位 200秒,超過 200秒 就自動死掉。

* * * * * timeout 200 php /home/app/email.php

如果這個指令碼執行時間超過 60秒,下一分鐘又會執行 php email.php,如果避免重複執行?

這樣會出現,有兩個程式同時在執行 php email.php,那會不會出現同一個任務被執行了兩次?


解決辦法:

使用 flock 進行互斥控制

用法:
 flock [選項] <檔案|目錄> <命令> [<引數>...]
 flock [選項] <檔案|目錄> -c <命令>
 flock [選項] <檔案描述符號碼>

通過 shell 指令碼管理檔案鎖。

選項:
 -s, --shared             獲取共享鎖
 -x, --exclusive          獲取排他鎖(預設)
 -u, --unlock             移除鎖
 -n, --nonblock           失敗而非等待
 -w, --timeout <秒>       等待限定的時間
 -E, --conflict-exit-code <數字>     衝突或超時後的退出程式碼
 -o, --close              執行命令前關閉檔案描述符
 -c, --command <命令>      通過 shell 執行單個命令字串
 -F, --no-fork            執行命令時不 fork
     --verbose            增加詳盡程度

 -h, --help               display this help
 -V, --version            display version

我們用到其中的排他設定

* * * * * flock -xn /tmp/test.lock -c "timeout 200 php /home/app/email.php"

記錄好日誌

定時任務可能要記錄日誌呀,不然後期怎麼排查

* * * * * flock -xn /tmp/test.lock -c "timeout 200 php /home/app/email.php >> /home/log/test.log 2>&1" 

總結

* * * * * flock -xn /tmp/test.lock -c "timeout 200 php /home/app/email.php >> /home/log/test.log 2>&1" 

番外篇 頻率提升

我覺得一分鐘一次頻率太低,想 10s 執行一次怎麼辦?

* * * * * php /home/app/email.php >> /home/log/test.log 2>&1
* * * * * ( sleep 10 ; php /home/app/email.php >> /home/log/test.log 2>&1 )
* * * * * ( sleep 20 ; php /home/app/email.php >> /home/log/test.log 2>&1 )
* * * * * ( sleep 30 ; php /home/app/email.php >> /home/log/test.log 2>&1 )
* * * * * ( sleep 40 ; php /home/app/email.php >> /home/log/test.log 2>&1 )
* * * * * ( sleep 50 ; php /home/app/email.php >> /home/log/test.log 2>&1 )

番外篇 flock 測試

準備一個 php 指令碼 /home/rovast/Code/flock/test.php

<?php

$i = 10000;
while ($i > 0) {
  echo --$i . \PHP_EOL;
  sleep(1);
}

執行

flock -xn /tmp/mytest.lock -c "timeout 30 php /home/rovast/Code/flock/test.php"

我們看到終端不停輸出數值

9999
9998
9997
9996
9995
9994
9993
9992
9991
9990

我們再開啟另外一個終端,執行

flock -xn /tmp/mytest.lock -c "timeout 30 php /home/rovast/Code/flock/test.php"

我們發現:

  1. 第二次執行的沒有輸出(因為 flock 互斥)
  2. 第一個執行的,30秒後自動關閉程式(因為 timeout 30)

相關文章