Reputation: 100496
In some Node.js scripts that I have written, I notice that even if the last line is a synchronous call, sometimes it doesn't complete before Node.js exits.
I have never seen a console.log
statement fail to run/complete before exiting, but I have seen some other statements fail to complete before exiting, and I believe they are all synchronous. I could see why the callback of an async function would fail to fire of course in this case.
The code in question is a ZeroMQ .send()
call like so:
var zmq = require('zmq');
var pub = zmq.socket('pub');
pub.bindSync('tcp://127.0.0.1:5555');
setInterval(function(){
pub.send('polyglot');
},500);
The above code works as expected...but if I remove setInterval()
and just call it like this:
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);
...Then the message will not get delivered - the program will apparently exit before the pub.send()
call completes.
What is the best way to ensure a statement completes before exiting in Node.js ? Shutdown hooks would work here, but I am afraid that would just be masking the problem since you can't put everything that you need to ensure runs in a shutdown hook.
This problem can also be demonstrated this way:
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.');
}
I believe this is a legit/serious problem because a lot of programs just need to publish messages and then die, but how can we effectively ensure all messages get sent (though not necessarily received)?
EDIT: One (potential) way to fix this is to do:
socket.send('xyz');
socket.close(); // supposedly this will block until the above message is sent
process.exit(0);
Upvotes: 17
Views: 917
Reputation: 100496
I think the simple answer is the the socket.send()
method is in fact asynchronous and that is why we see the behavior I described in the OP.
The question then is - why does socket.send()
have to be asynchronous - could there not be a blocking/synchronous version that we could use instead for the purpose intended in the OP? Could we please have socket.sendSync()
?
Upvotes: 0
Reputation: 7629
Diving into zeromq.node, you can see what Socket.send
just pushes your data to _outgoing
:
this._outgoing.push([msg, flags]);
... and then calls _flush
iff zmq.ZMQ_SNDMORE is unset:
this._flush();
Looks like _flush
is actually doing the socket write. If _flush()
fails, it emits an error.
Edit:
I'm guessing calling pub.unbind()
before exiting, will force the _flush()
to be called:
pub.unbind('tcp://127.0.0.1:5555', function(err) {
if (err) console.log(err);
process.exit(0); // Probably not even needed
});
Upvotes: 8