2013-11-01 28 views
0

我正在嘗試構建作業調度程序。我有一份要在2-3臺不同的計算機上按時執行的作業的列表。因此,任何機器都可以選擇任何作業,並且如果其next_execution_time < current_time將執行它。我將所有作業存儲在數據庫表中,並且在SQL中使用SELECT.... FOR UPDATE查詢來選擇要執行的作業。在數據庫表的一行上讀取鎖定

但是這種方法的問題是,如果machine1選擇了一個作業,因爲只有寫鎖定,其他機器也會選擇相同的作業執行,但不能執行,因爲它們將等待要釋放的鎖定或鎖定超時將發生。那麼有什麼辦法可以讓其他機器跳過這個作業並使用SQL鎖執行其他作業。數據庫中不應該添加其他列?

流程是這樣的:

select a job and lock it -> execute the job -> release the lock 

我使用的Ruby-on-Rails使用開發這個。如果在rails中沒有等待或set_lock_timeout = 0。它可能可以解決問題。如果存在......語法是什麼?

+0

您可以爲正在處理的行設置標誌,例如'being_processed =「Y」'並通過'being_processed!=「Y」'過濾行。 – fedorqui

+1

@fedorqui是的,我正在使用額外的列「locked_by」= machine_ip來檢查作業是否被鎖定/執行,但這不被推薦,因爲如果一臺機器在執行任務時發生故障,鎖定將永遠不會被髮布。 –

+0

是的,你是對的。你也可以使用'redis'來設置一個標誌,並在一段時間後過期。 – fedorqui

回答

0

實際上,你有一個簡單的方法來處理你當前在mysql中的表,你需要在選擇下一個任務時臨時鎖定表。我假設你在表中旗已經開始/完成的任務欄,否則,你可以使用相同的列和datetime開始工作,它已完成標誌/啓動:

lock tables jobs write; 

select * from jobs where start_time < current_time and status = 'pending' order by start_time; 
-- be carefull here to check for SQL errors in your code and run unlock tables if an exception is thrown or something like that 

update jobs set status = 'started' where id = the_one_you_selected_adobe; 

unlock tables; 

就是這樣,多個併發線程/進程cab使用作業表來執行任務,而無需2個線程運行相同的任務。

+0

感謝您的快速回復。我一直在使用相同的方法,但問題是如果一臺機器在執行任務時發生故障,狀態將永遠不會改變,並且永遠不會執行此任務,因爲狀態將始終啓動。所以我問是否有任何內部鎖定技術在SQL服務器級別,這將自己照顧這個鎖定機制。 –

+0

對不起,延遲是,有這樣一種機制,它被稱爲交易。具體實現可能會有所不同,具體取決於您使用的引擎(我假設您使用MySQL作爲問題上的標籤),但innoDB def支持事務。這個想法是一樣的,您需要從表中讀取(選擇)下一個任務,並將任務的狀態更新爲「啓動」或類似於事務內部的任務,DBMS將負責其餘部分。 –