Node.js socket.send()函数在退出前无法完成

在我编写的一些Node.js脚本中,我注意到即使最后一行是同步调用,有时在Node.js退出之前也不会完成。

我从来没有见过一个console.log语句在退出之前无法运行/完成,但是我已经看到一些其他语句在退出之前无法完成,我相信它们都是同步的。 我可以看到为什么在这种情况下,asynchronous函数的callback将无法启动。

有问题的代码是一个ZeroMQ .send()调用如下所示:

  var zmq = require('zmq'); var pub = zmq.socket('pub'); pub.bindSync('tcp://127.0.0.1:5555'); setInterval(function(){ pub.send('polyglot'); },500); 

上面的代码按预期工作…但是,如果我删除setInterval() ,只是这样调用它:

  var zmq = require('zmq'); var pub = zmq.socket('pub'); pub.bindSync('tcp://127.0.0.1:5555'); pub.send('polyglot'); //this message does not get delivered before exit process.exit(0); 

那么这个消息就不会被传递 – 程序在pub.send()调用完成之前显然会退出。

在退出Node.js之前,确保语句完成的最佳方法是什么? closures钩子可以在这里工作,但是恐怕只是掩盖了问题,因为你不能把你需要的所有东西都保证在closures钩子中运行。

这个问题也可以用这种方式来certificate:

  if (typeof messageHandler[nameOfHandlerFunction] == 'function') { reply.send('Success'); messageHandler[nameOfHandlerFunction](null, args); } else { reply.send('Failure'); //***this call might not complete before the error is thrown below.*** throw new Error('SmartConnect error: no handler for ZMQ message sent from Redis CSV uploader.'); } 

我认为这是一个合法/严重的问题,因为很多程序只需要发布消息然后死掉,但是我们怎么才能有效地确保所有的消息都被发送(虽然不一定收到)呢?

编辑:一个(潜在)的方法来解决这个问题是:

 socket.send('xyz'); socket.close(); // supposedly this will block until the above message is sent process.exit(0); 

深入zeromq.node ,你可以看到什么Socket.send只是推动你的数据_outgoing

 this._outgoing.push([msg, flags]); 

…然后调用_flush iff zmq.ZMQ_SNDMORE未设置 :

 this._flush(); 

看起来_flush实际上是在写套接字 。 如果_flush()失败, 则会发出错误 。

编辑:

我猜在退出之前调用pub.unbind()会强制调用pub.unbind()

 pub.unbind('tcp://127.0.0.1:5555', function(err) { if (err) console.log(err); process.exit(0); // Probably not even needed }); 

我认为简单的答案是socket.send()方法实际上是asynchronous的 ,这就是为什么我们看到我在OP中描述的行为。 接下来的问题是,为什么socket.send()必须是asynchronous的 – 我们可以使用阻塞/同步版本来代替OP中的目的吗? 我们可以请有socket.sendSync() ? K谢谢