最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Node.js socket.send( ) functions failing to complete before exit - Stack Overflow

programmeradmin3浏览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);

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
 |  Show 6 more ments

2 Answers 2

Reset to default 8 +25

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

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()?

发布评论

评论列表(0)

  1. 暂无评论