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 plete before Node.js exits.
I have never seen a console.log
statement fail to run/plete before exiting, but I have seen some other statements fail to plete 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 pletes.
What is the best way to ensure a statement pletes 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 plete 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);
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 plete before Node.js exits.
I have never seen a console.log
statement fail to run/plete before exiting, but I have seen some other statements fail to plete 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 pletes.
What is the best way to ensure a statement pletes 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 plete 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);
Share
Improve this question
edited May 8, 2015 at 19:44
Alexander Mills
asked Apr 27, 2015 at 21:52
Alexander MillsAlexander Mills
101k166 gold badges537 silver badges918 bronze badges
11
- by design a synchronous script will run to pletion unless process.exit() is called, so you're going to have to show some code in this case. Otherwise it'll just be guess work about something that might not even actually be true. – Mike 'Pomax' Kamermans Commented Apr 27, 2015 at 21:55
- 2 You cannot guarantee async pletion in a shutdown hook. – SLaks Commented Apr 27, 2015 at 21:56
- 1 could try wrapping it in a setTimeout with 0? – Ed Knowles Commented Apr 27, 2015 at 21:59
- I added the code in question, please let me know what you think – Alexander Mills Commented Apr 27, 2015 at 22:36
-
2
Why are you calling
process.exit(0)
? A node process will terminate if it is finished (close connections, stop listening, etc.). Also, pretty much anything that does I/O in node is async. Not taking a callback doesn't mean it is synchronous - it just means that you can't find out when it's done. – Aaron Dufour Commented May 2, 2015 at 5:38
2 Answers
Reset to default 8 +25Diving 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
});
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()
?