使Meteor.methods同步和异步

Nyx*_*nyx 5 javascript multithreading asynchronous node.js meteor

有时我需要将Meteor.call writeMeLater排队并同步执行(阻止writeMeLater来自同一客户端的其他调用).

其他时候writeMeLater应该尽快执行呼叫,而不排队当前排队的所有呼叫.

以下是我使用this.unblock()if 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)
Run Code Online (Sandbox Code Playgroud)

案例2(正确异步):

Meteor.call('writeMeLater', 'a', true)
Meteor.call('writeMeLater', 'a', true)
Meteor.call('writeMeLater', 'a', true)
Run Code Online (Sandbox Code Playgroud)

案例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)
Run Code Online (Sandbox Code Playgroud)

服务器/ 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)
    }

})
Run Code Online (Sandbox Code Playgroud)

Geo*_*oth 2

我的第一个想法是,为什么不实际创建一个队列呢?而不是依赖 JavaScript 事件循环作为队列。然后将文档插入该队列,例如:

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

也许每次插入高优先级写入时,都会触发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);
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望每次插入高优先级或低优先级写入时都处理队列,请write随时调用该方法或将其放入insert方法write本身中。这解决了跳转到行头的问题,尽管写入仍然是每个客户端同步处理的。

至于尝试为单个客户端实现并行处理,@imslavko(在上面问题的评论中)是正确的,因为实现此目的的一种方法是客户端建立多个 DDP 连接。有一个相对简单的方法,尽管有点 hacky 和非 Meteoric:

安装Iron Router并在服务器代码中定义服务器端路由:

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

上面this.request.query是一个带有您随请求提交的键值对的对象。例如:

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

据服务器所知,这个请求来自一个新的客户端,因此它将在一个新的 Fiber(即线程)中处理。如果该writeMeLater方法知道不等待,则它的许多实例可以开始同时运行。现在问题就变成了保持请求的顺序,如果服务器上的执行顺序与客户端上的执行顺序相同对您来说很重要,因为 HTTP POST 请求不一定按照与原来相同的顺序到达服务器发送。但也有多种处理方法(批量发送它们,或者包含一个计数器,并让服务器在检测到不按顺序的请求时等待几秒钟等)。