4

I've written up a minimal example of this. The code is posted here: https://gist.github.com/1524725

I start my server, start my client, verify that the connection between the two is successful, and finally kill the server with CTRL+C. When the server dies, the client immediately runs to completion and closes without printing the message in either on_client_close or on_client_disconnect. There is no perceptible delay.

From the reading I've done, because the client process is terminating normally there isn't any chance that the STDOUT buffer isn't being flushed.

It may also be worth noting that when I kill the client instead of the server, the server responds as expected, firing the on_ws_disconnect function and removing the client connection from its list of active clients.

32-bit Ubuntu 11.10 Socket.io v0.8.7 Socket.io-client v0.8.7 NodeJS v0.6.0

Thanks!

--- EDIT ---

Please note that both the client and the server are Node.js processes rather than the conventional web browser client and node.js server.

zslayton
  • 51,416
  • 9
  • 35
  • 50

1 Answers1

5

NEW ANSWER

Definitely a bug in io-client. :(

I was able to fix this by modifying socket.io-client/libs/socket.js. Around line 433, I simply moved the this.publish('disconnect', reason); above if (wasConnected) {.

Socket.prototype.onDisconnect = function (reason) {
    var wasConnected = this.connected;

    this.publish('disconnect', reason);

    this.connected = false;
    this.connecting = false;
    this.open = false;

    if (wasConnected) {
      this.transport.close();
      this.transport.clearTimeouts();

After pressing ctrl+c, the disconnect message fires in roughly ten seconds.

OLD DISCUSSION

To notify client of shutdown events, you would add something like this to demo_server.js:

var logger = io.log;

process.on('uncaughtException', function (err) {
  if( io && io.socket ) {
     io.socket.broadcast.send({type: 'error', msg: err.toString(), stack: err.stack});
  }
  logger.error(err);
  logger.error(err.stack);

  //todo should we have some default resetting (restart server?)
  app.close();
  process.exit(-1);
});

process.on('SIGHUP', function () {
  logger.error('Got SIGHUP signal.');
  if( io && io.socket ) {
     io.socket.broadcast.send({type: 'error', msg: 'server disconnected with SIGHUP'});
  }
  //todo what happens on a sighup??
  //todo if you're using upstart, just call restart node demo_server.js
});

process.on('SIGTERM', function() {
  logger.error('Shutting down.');
  if( io && io.socket ) {
     io.socket.broadcast.send({type: 'error', msg: 'server disconnected with SIGTERM'});
  }
  app.close();
  process.exit(-1);
});

Of course, what you send in the broadcast.send(...) (or even which command you use there) depends on your preference and client structure.

For the client side, you can tell if the server connection is lost using on('disconnect', ...), which you have in your example:

client.on('disconnect', function(data) {
   alert('disconnected from server; reconnecting...');
   // and so on...
});
Kato
  • 40,352
  • 6
  • 119
  • 149
  • This is very reasonable, but not really what I'm looking for. There are instances in which the server could die without having the opportunity to clean up after itself. Consider the SIGKILL signal, which cannot be caught, or a power failure. Clearly the client side knows that the server has gone away because it runs to completion -- what I'd like is for the client to reliably fire a callback allowing it to perform certain actions in this event. Thank you for your input, though! – zslayton Dec 27 '11 at 20:22
  • So what you're looking for is a way, on the client, to tell if the connection to the server times out? I think you just need to replace "disconnect" with "disconnected"; I don't know where I found this, but I use it on my node apps (example added to my answer) – Kato Dec 27 '11 at 20:35
  • Also, don't forget that you can tell the client to reconnect automagically: io_client.connect(url, {reconnect: true}); – Kato Dec 27 '11 at 20:38
  • Either a timeout or a closed socket, yes. I just tried switching 'disconnect' to 'disconnected' but unfortunately the behavior didn't change. I also tried having an event for both 'disconnect' and 'disconnected' (instead of replacing the former with the latter), but to no avail. Thank you for your continued assistance! – zslayton Dec 27 '11 at 20:41
  • I notice that your client example includes a call to 'alert()' -- I should emphasize (and will edit my original post to indicate this) that my client is socket.io-client, a node.js library, and not a web browser. – zslayton Dec 27 '11 at 20:44
  • I did notice you were using socket.io-client; just missed a line in my copy/paste; let me see if I can find out why disconnected works for me, perhaps it's specific to socket.connect()? – Kato Dec 27 '11 at 21:05
  • No. I discovered that I had two methods: `on('disconnect')` (just like yours) and another on('disconnected') fired by the server. Ironically, my 'disconnect' is run even on a ctrl+c by the server. I think it might be getting called in app.close()? Maybe something provided by Express? Still wondering... – Kato Dec 27 '11 at 21:22
  • @Zack - I've found the error and a fix for it; it was a very intriguing problem as I'm working along the same lines right now in node! I'll add a note to your bug report (which I noticed on github) – Kato Dec 27 '11 at 22:24