2014-01-20 142 views
5

有時我需要Meteor.call到writeMeLater排隊和同步執行(阻止來自同一客戶端的其他調用writeMeLater)。使Meteor.methods同步和異步

其他時候應該儘快執行writeMeLater的呼叫,而不排隊等待當前排隊的所有呼叫。

以下是我嘗試使用this.unblock()如果async參數爲true。案例1和2工作正常。但在案例3中,撥打async=true的電話正在排隊等待async=false!我們怎樣才能撥打async=true跳過隊列?這將是類似於如何從第二個客戶端從第一客戶端調用後不排隊呼叫,

所有Meteor.call()從客戶端進行

案例1(正常同步):

Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 

案例2(正確地異步):

Meteor.call('writeMeLater', 'a', true) 
Meteor.call('writeMeLater', 'a', true) 
Meteor.call('writeMeLater', 'a', true) 

案例3(不期望的行爲)

Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 

Meteor.call('writeMeLater', 'a', true) 
Meteor.call('writeMeLater', 'a', true) 
Meteor.call('writeMeLater', 'a', true) 

服務器/ main.js

writeMeLater = function(data, callback) { 
    console.log('writeMeLater: ', data) 

    // simulate taking 3 second to complete 
    Meteor.setTimeout(function() { 
     Logs.insert({data: data, timestamp: new Date().getTime()}) 
     console.log('Log.insert: ', data) 
     callback(null, 'done') 
    }, 3 * 1000) 
} 



writeMeLaterSync = Meteor._wrapAsync(writeMeLater) 



Meteor.methods({ 

    writeMeLater: function(data, async) { 
     if(async) 
      this.unblock() 

     writeMeLaterSync(data) 
    } 

}) 
+0

你期望什麼? – imslavko

+0

@imslavko是否可以立即執行一些方法調用而不是排隊,類似於來自不同客戶端的方法調用不在來自第一客戶端 – Nyxynyx

+0

的調用之後排隊,這正是'this.unblock() 'call會做 - 它將允許另一個方法調用當前連接到* start *,然後完成上一個操作。這是我看到的輸出:http://pastebin.com/gtdgLTGf它看起來對我來說是正確的。對於3個同步呼叫,在呼叫結束前有3秒延遲。對於第二批 - 它們都在同一時間開始並在3秒後結束。 – imslavko

回答

2

我首先想到的是,爲什麼沒有真正創建隊列?而不是依靠JavaScript事件循環作爲您的隊列。然後將文檔轉換爲隊列,如:

WritesQueue = new Meteor.Collection("WritesQueue"); 
WritesQueue.insert({data: 'a', prioritize: true, inserted: new Date()}); 

也許你插入每一次高優先級寫入,引發Meteor.call("write")它處理隊列,與優先級(非異步)的人會第一:

Meteor.methods({ 
    write: function() { 
    WritesQueue.find({prioritize: true}, {sort: {inserted: 1}}) 
    .forEach(function (doc) { 
     console.log(doc.data); 
     WritesQueue.remove(doc._id); 
    }); 
    WritesQueue.find({prioritize: false}, {sort: {inserted: 1}}) 
    .forEach(function (doc) { 
     console.log(doc.data); 
     WritesQueue.remove(doc._id); 
    }); 
    } 
}); 

或者,如果你想處理的每次插入高或低優先級的寫,要麼調用write方法無論是時間還是把insertwrite方法本身裏面的時間排隊。這解決了跳到頭部的問題,儘管寫入仍然是同步處理每個客戶端。

至於嘗試爲單個客戶端實現並行處理,@imslavko(在上述問題的註釋中)是正確的,因爲實現此目的的一種方式是讓客戶端建立多個DDP連接。有一個比較簡單的,雖然哈克和非白水臺,辦法做到這一點:

安裝Iron Router和服務器代碼,定義一個服務器端路線:

Router.map(function() { 
    this.route('writeMeLater', { 
    where: 'server', 
    action: function() { 
     Meteor.call('writeMeLater', 
     this.request.query.data, this.request.query.async); 
    } 
    }); 
}); 

以上this.request.query與對象您通過請求提交的鍵值對。例如:

HTTP.post("http://yoursite.com/writeMeLater", 
    {params: {data: 'a', async: true}}); 

至於服務器知道,這個請求是從一個新的客戶端的到來,所以它會在一個新的光纖(即線程)進行處理。如果writeMeLater方法知道不等待,則它的許多實例可以同時開始運行。現在問題就是如何保持請求的順序,如果服務器上的執行順序與客戶端上的順序相同對您來說很重要,因爲HTTP POST請求可能不一定以與它們相同的順序到達服務器發送。但是也有不同的處理方式(分批發送它們,或者包括一個計數器,並且如果服務器檢測到無序請求等,則讓服務器等待幾秒鐘)。