2012-10-29 38 views
6

有一個問題,我的一個團隊成員正在使用PHP進行排隊過程。 PHP腳本在命令行上運行,並在每個週期後遞歸調用自己,以檢查數據庫中是否有任何項目正在等待處理。如果存在,則自行分叉,處理隊列中的項目並重復。如果什麼都沒有,它就會死亡,並且一個cron作業每5分鐘就會重新啓動隊列。PHP隊列問題 - 冗餘進程

偶爾會有兩個進程同時運行,抓取相同的隊列,並相互進入。我正考慮在喚醒過程中引入抖動,以便在啓動過程之間有一段隨機的時間。

有沒有更好的方法?

回答

4

抖動只是使得碰撞難以預測。

在磁盤上放置一個互斥鎖。檢查它是否比兩個週期前更早。如果是,請忽略並刪除它;它由於墜毀事件而落後了。否則,有一個已經運行,所以保釋。

2

如果您的隊列中的項目不必執行,您可以做這樣的事情,只是讓兩個進程並行運行。

選擇從隊列中下一個作業(顯然語法將取決於數據庫)

LOCK TABLE queue; 

SELECT * FROM queue WHERE status <> 'INPROGRESS' ORDER BY id LIMIT 1 

UPDATE queue SET status = 'INPROGRESS' WHERE id = ? 

UNLOCK TABLES; 

做的工作,然後標記任務已完成或如果你想找到被困在地獄的工作從隊列

刪除,你可以存儲一個作業開始的時間戳,並把它放回隊列,如果它在那裏多於x分鐘

0

LOCK TABLE queue;是有點矯枉過正,因爲它看起來是整個表,所以根本沒有併發。如果使用現場更新方法,則根本不需要鎖定(狀態更新爲INPROGRESS)。 SQL更新操作在內部執行鎖定,所以像這樣的事情必須同時工作:

UPDATE queue SET consumer_id='a_consumer_unique_id' status='INPROGRESS' LIMIT 1 

SELECT * FROM queue WHERE consumer_id='a_consumer_unique_id' LIMIT 1 

但是這種方法有副作用。我們必須更改標誌INPROGRESS或設置consumer_id。如果消費者偷看消息(consumer_id設置爲它)並且消失了消息會發生什麼?它會長時間呆在隊列中,所以你需要一種清理腳本來處理這些情況。

我們可以做的是將消息標記爲我們的,加載到內存並從隊列中刪除它。只有在完成之後,我們纔會開始處理它。這是如何enqueue/dbal做到這一點。

如果您需要重新交付擔保,請使用像RabbitMQ這樣的真正經紀商。