【问题标题】:Node.js socket.send( ) functions failing to complete before exitNode.js socket.send() 函数在退出前未能完成
【发布时间】:2023-03-14 15:47:02
【问题描述】:

在我编写的一些 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 之前确保语句完成的最佳方法是什么?关闭挂钩在这里可以工作,但我担心这只会掩盖问题,因为您无法将确保运行所需的所有内容都放在关闭挂钩中。

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

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

【问题讨论】:

  • 按照设计,除非 process.exit() 被调用,否则同步脚本将运行到完成,因此在这种情况下您将不得不显示一些代码。否则,这只是对某些甚至可能不是真的事情的猜测。
  • 您不能保证关闭挂钩中的异步完成。
  • 可以尝试用 0 将其包装在 setTimeout 中吗?
  • 我添加了有问题的代码,请告诉我你的想法
  • 你为什么打电话给process.exit(0)?如果节点进程完成(关闭连接、停止侦听等),它将终止。此外,几乎所有在节点中执行 I/O 的操作都是异步的。不接受回调并不意味着它是同步的——它只是意味着你无法知道它何时完成。

标签: javascript node.js zeromq


【解决方案1】:

潜入zeromq.node,你可以看到Socket.send只是pushes your data to _outgoing

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

...然后calls _flush iff zmq.ZMQ_SNDMORE is unset:

this._flush();

看起来像_flush is actually doing the socket write。如果_flush() 失败,it emits an error

编辑:

我猜想在退出之前调用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
});

【讨论】:

  • 我不认为“过早”退出会导致 _flush( ) 失败。什么都没有失败,只是我的 node.js 进程不知道它需要等到 zmq 代码完成
  • 请查看我的编辑 - 如果我们抛出错误,而不是 process.exit(),可能会出现同样的问题。
【解决方案2】:

我认为简单的答案是socket.send() 方法实际上是异步,这就是我们看到我在 OP 中描述的行为的原因。

然后的问题是 - 为什么socket.send() 必须是异步的 - 是否没有我们可以用于 OP 中预期目的的阻塞/同步版本?请问socket.sendSync()可以吗?

【讨论】:

    猜你喜欢
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多