2011-12-01 53 views
2

我想用MongoDB實現一個相當簡單的隊列。我有一些麻煩的工作人員需要處理的集合。每個工作人員應該蒐集未處理的工作集合,然後執行它。MongoDB中相當簡單的基於時間的隊列

我決定哪個工作是未處理的方式是基於一個簡單的計算。

基本上我有哪些需要在特定的時間段,其中的間隔存儲在每個文檔interval中要執行的任務集合,工作人員將掃描的集合,它沒有更新,至少在interval時間的文件。

文檔(_id場略)的一個例子是:

{ 
    updated: 0360, 
    interval: 60, 
    work: "an object representing the work" 
} 

我要的是一個原子/阻擋查詢(有多個工人)返回一個批處理文件,其中updated + interval < currentTime,其中currentTime是數據庫服務器上的時間,以及將updated字段設置爲currentTime

換句話說:

  1. 發現:更新+間隔< currentTime的
  2. 回了一批這些,說30
  3. 集:更新= currentTime的

任何幫助是很大的不勝感激!

回答

3

因爲MongoDB不支持事務處理,所以你不能安全地對一批物品進行悲觀鎖定,除非你有一個單獨的文檔 - 更多的在最後。

讓我們從查詢開始:你不能查詢某物。比如'where x + y < z'在MongoDB中。相反,您必須爲下一個到期日期使用字段,例如nextDue

{ 
    "nextDue": "420", 
    "work": { ... } 
} 

現在每個工人可以賣到幾個項目的(注:這是所有的僞代碼,而不是特定的編程語言):

var result = db.queue.find({ "nextDue": { $gt, startTime } }).limit(50); 
// hint: you can do a random skip here to decrease the chances of collisions 
// between workers. 

foreach(rover in result) 
{ 
    // pessimistic locking: '-1' indicates this is in progress. 
    // I'd recommend a flag instead, however... 

    var currentItem = db.queue.findAndModify({ "_id" : rover.id, "nextDue" : {$gt, startTime}}, {$set : {"nextDue" : -1}}); 

    if(currentItem == null) 
     continue; // hit a lock: another worker is processing this already 

    // ... process job ... 

    db.queue.findAndModify({ "_id" : rover.id, "nextDue" : "-1"}, {$set : {"nextDue" : yourNextDue }}); 
} 

主要有兩種方法,我看到悲觀鎖定多個文件。一個是爲您要鎖定的文檔創建存儲桶,將作業描述符放入存儲桶並處理這些存儲桶。從現在開始,這個桶是一個單獨的對象,你可以依賴原子修飾符。

另一個是使用two-phase commit,它也爲交易創建另一個對象,但不要求您將文檔移動到不同的文檔中。但是,這是一個有點複雜的模式。

上面介紹的僞代碼在兩個應用程序中工作得很好,但是在兩個應用程序中,各個作業都花了相當長的時間來執行(半秒到幾個小時)。