2014-01-20 260 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请求可能不一定以与它们相同的顺序到达服务器发送。但是也有不同的处理方式(分批发送它们,或者包括一个计数器,并且如果服务器检测到无序请求等,则让服务器等待几秒钟)。