如何解决Node.js socket.send()函数在退出前无法完成的错误?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (50)

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

我从来没有看到console.log在退出之前没有完成运行/完成的声明,但是我已经看到一些其他声明在退出之前未能完成,我相信它们都是同步的。

有问题的代码是这样的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之前确保语句完成的最佳方法是什么?Shutdown钩子可以在这里工作,但是我担心这只会掩盖问题,因为你不能把你需要的所有东西都保证在关闭钩子中运行。

这个问题也可以这样说明:

 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]);

然后调用_flushiff zmq.ZMQ_SNDMORE未设置:

this._flush();

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

我猜pub.unbind()在退出之前调用会迫使_flush()被称为:

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

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

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动