Node.js socket.send( ) 函数在退出前未能完成
Node.js socket.send( ) functions failing to complete before exit
在我写的一些 Node.js 脚本中,我注意到即使最后一行是同步调用,有时在 Node.js 退出之前它也没有完成。
我从未见过 console.log
语句在退出前失败到 run/complete,但我见过其他一些语句在退出前未能完成,我相信它们都是同步的。我明白为什么在这种情况下异步函数的回调当然会失败。
有问题的代码是 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.');
}
我认为这是一个legit/serious问题,因为很多程序只需要发布消息然后就死掉了,但是我们如何才能有效地确保所有消息都发送出去(尽管不一定收到)?
编辑:
解决此问题的一种(潜在)方法是:
socket.send('xyz');
socket.close(); // supposedly this will block until the above message is sent
process.exit(0);
潜入 zeromq.node, you can see what Socket.send
just 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. If _flush()
fails, 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
});
我认为简单的答案是 socket.send()
方法实际上是 异步的 这就是我们看到我在 OP 中描述的行为的原因。
那么问题是 - 为什么 socket.send()
必须是异步的 - 难道没有一个 blocking/synchronous 版本我们可以用来代替 OP 中的预期目的吗?我们可以 socket.sendSync()
吗?
在我写的一些 Node.js 脚本中,我注意到即使最后一行是同步调用,有时在 Node.js 退出之前它也没有完成。
我从未见过 console.log
语句在退出前失败到 run/complete,但我见过其他一些语句在退出前未能完成,我相信它们都是同步的。我明白为什么在这种情况下异步函数的回调当然会失败。
有问题的代码是 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.');
}
我认为这是一个legit/serious问题,因为很多程序只需要发布消息然后就死掉了,但是我们如何才能有效地确保所有消息都发送出去(尽管不一定收到)?
编辑: 解决此问题的一种(潜在)方法是:
socket.send('xyz');
socket.close(); // supposedly this will block until the above message is sent
process.exit(0);
潜入 zeromq.node, you can see what Socket.send
just 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. If _flush()
fails, 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
});
我认为简单的答案是 socket.send()
方法实际上是 异步的 这就是我们看到我在 OP 中描述的行为的原因。
那么问题是 - 为什么 socket.send()
必须是异步的 - 难道没有一个 blocking/synchronous 版本我们可以用来代替 OP 中的预期目的吗?我们可以 socket.sendSync()
吗?