2014-01-20 60 views
5

時々、Meteor.callをwriteMeLaterにして、キューに入れて同期的に実行する必要があります(同じクライアントからwriteMeLaterへの他の呼び出しをブロックする)。Meteor.methodsを同期非同期にする

writeMeLaterへの呼び出しは、現在キューに入れられているすべてのコールの後にキューイングすることなく、できるだけ早く実行する必要があります。

asyncパラメータがtrueの場合、this.unblock()を使用して私の試みを以下に示します。ケース1と2はうまく動作します。しかし、ケース3ではasync=trueのコールがasync=falseのコールの後にキューに入れられています! async=trueで通話をスキップするにはどうすればよいですか?

Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 
Meteor.call('writeMeLater', 's', false) 
:これはすべて Meteor.call()がクライアント

ケース1(正しく同期)から作られています

、最初のクライアントからの呼び出しの後にキューイングされていない2番目のクライアントから呼び出す方法のようになります。

ケース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() '呼び出しはこれを行います - これは、前の接続が完了する前に、* start *への現在の接続を別のメソッド呼び出しで許可します。それは私が見る出力です:http://pastebin.com/gtdgLTGfそしてそれは私に見えます。 3つの同期コールの場合、コールが終了するまでに3秒の遅延があります。 2回目のバッチでは、それらはすべて同時に開始し、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メソッドを呼び出すか、またはwriteメソッド自体の内部にinsertメソッドを呼び出します。これは、書き込みがクライアントごとに同期して処理されますが、先頭の行にジャンプする問題を解決します。

単一のクライアントの並列処理を実現するために、@imslavko(上記のコメントにある)は正しいですが、これを実現する方法の1つはクライアントが複数の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を対象とはされてそれを行うために、比較的ハックはいえ、シンプルかつ非流星、方法がありますリクエストとともに提出したKey-Valueペア。たとえば:

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

限り、サーバーが知っているように、この要求が新しいクライアントから来ているので、新しいファイバ(すなわちスレッド)で処理されます。 writeMeLaterメソッドが待機しないことを知っている場合、そのインスタンスの多くのインスタンスが同時に実行を開始できます。今度は、HTTP POST要求がサーバーと同じ順序で必ずしもサーバーに到着しない可能性があるため、サーバー上の実行順序がクライアント上と同じであることが重要である場合、問題は順番に要求を保持するようになります送信されます。しかし、それを扱う方法はいろいろあります(バッチで送るか、カウンターを含めて、順序が狂ったリクエストなどを検出した場合にサーバーが数秒待つようにしてください)。