我有幾個由cron調用的php腳本。 cron作業每20分鐘運行一次。有時腳本會在幾分鐘內完成工作,有時需要超過20分鐘。網頁的單個實例
我想在這裏防止競爭條件。我想到的一種方式是在頁面運行時使用數據庫設置標誌,並在作業完成時刪除標誌。但我真的不想使用數據庫。
有沒有其他解決方案?
我有幾個由cron調用的php腳本。 cron作業每20分鐘運行一次。有時腳本會在幾分鐘內完成工作,有時需要超過20分鐘。網頁的單個實例
我想在這裏防止競爭條件。我想到的一種方式是在頁面運行時使用數據庫設置標誌,並在作業完成時刪除標誌。但我真的不想使用數據庫。
有沒有其他解決方案?
最好的方法(我用過)涉及將進程ID保存在「鎖定文件」中。
function getLock() {
//First, check to see if the script is already running
$data = @file_get_contents('path/to/process.pid');
if ($data && posix_kill($data, 0)) {
throw new RuntimeException(
'Unable To Attain Lock, Another Process Is Still Running'
);
}
file_put_contents('path/to/process.pid', posix_getpid());
}
基本上,它讀取文件,然後試圖posix_kill
裏面包含的pid。請注意,當您使用0
到posix_kill
的信號時,它只會告訴您呼叫是否成功(意味着該過程正在運行)。
這樣做有一個好處,即如果進程在沒有清理鎖定文件的情況下死掉,它會被檢測到並重新運行。
所以,當工作完成後,我需要只是取消鏈接PID文件?如果我殺了PHP進程會發生什麼? – Maximus 2010-08-02 15:49:35
您可以取消鏈接。這種方法的美妙之處在於你不必這樣做。所有文件都存儲'pid'。所以,即使你不解除鏈接,它仍然可以正常工作(只要另一個進程不是在同一個'pid'上啓動的,這不太可能)...如果該文件仍然存在,它會檢查看看存儲'pid'的進程是否仍在運行。如果不是(因爲它死了,你殺了它,或者它完成了),它會得到鎖並繼續執行...... – ircmaxell 2010-08-02 15:55:47
完美工作! – Maximus 2010-08-02 17:41:49
您可以使用flock()
鎖定預定義的「標誌」文件,並在啓動腳本之前檢查該文件是否仍然鎖定。
我不會推薦這個,如果腳本死了怎麼辦? – thecodeassassin 2010-08-02 12:47:01
是的,因爲這個原因,我沒有使用文件鎖定 – Maximus 2010-08-02 13:11:39
正確 - 你可以使用某種超時,但它可能無法在這個頻繁的任務中工作。 – 2010-08-02 13:15:04
當然,臨時文件=]
或fork過程。查看更多關於分叉位置:http://php.net/manual/en/function.pcntl-fork.php
建議:http://www.saynotoflash.com/archives/multi-process-php-execution/
你可以使用一個標記文件或共享內存區,或任何的進程間通信的其他正常形式。鍍金解決方案將實施一個小批量排隊過程。
你可以提供一個例子嗎? – Maximus 2010-08-02 12:50:39
作業正在運行時創建文件,並在作業完成後將其刪除。如果作業再次運行,而另一個作業正在運行,則在開始之前檢查此文件。 – jigfox 2010-08-02 12:54:01
批處理隊列處理?對不起,我不能。我真的是VMS男人,VMS包括批處理。你想要的是一個小程序,它讀取一個包含作業列表的文件,當它找到一個文件時,執行它,然後從文件中刪除它。這涉及到一些進程同步。克倫職位不會執行這項工作;他們會向文件附加一個請求。有人必須這樣做,也許網絡的一點拖網可能會出現一些東西。 – 2010-08-02 12:54:54
如果您創建一個pid文件來指示進程正在運行,請確保檢查文件的創建時間,並且已經設置了一個閾值,以確定過長的時間。這樣,如果你的工作在它有機會刪除它的pid文件之前就消失了,你的工作就不會停下來。
每30分鐘運行一次cron作業? ;-) – Scharron 2010-08-02 12:44:55
謝謝你的建議。它必須每20分鐘運行;) – Maximus 2010-08-02 12:50:21