cluster: wait on servers closing before disconnect
authorOleg Elifantiev <oleg@elifantiev.ru>
Tue, 2 Jun 2015 20:23:31 +0000 (23:23 +0300)
committerSam Roberts <sam@strongloop.com>
Tue, 9 Jun 2015 17:41:38 +0000 (10:41 -0700)
Before this, cluster behaves not the way it is documented.  When
disconnect is triggered, worker must wait for every server is closed
before doing disconnect actually.

Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
PR-URL: https://github.com/nodejs/io.js/pull/1400
Fixes: https://github.com/nodejs/io.js/issues/1305

lib/cluster.js
test/parallel/test-cluster-worker-wait-server-close.js [new file with mode: 0644]

index ca1005b..bb4b60a 100644 (file)
@@ -627,12 +627,26 @@ function workerInit() {
 
   Worker.prototype.disconnect = function() {
     this.suicide = true;
+    var waitingHandles = 0;
+
+    function checkRemainingHandles() {
+      waitingHandles--;
+      if (waitingHandles === 0) {
+        process.disconnect();
+      }
+    }
+
     for (var key in handles) {
       var handle = handles[key];
       delete handles[key];
-      handle.close();
+      waitingHandles++;
+      handle.owner.close(checkRemainingHandles);
     }
-    process.disconnect();
+
+    if (waitingHandles === 0) {
+      process.disconnect();
+    }
+
   };
 
   Worker.prototype.destroy = function() {
diff --git a/test/parallel/test-cluster-worker-wait-server-close.js b/test/parallel/test-cluster-worker-wait-server-close.js
new file mode 100644 (file)
index 0000000..0f1836c
--- /dev/null
@@ -0,0 +1,42 @@
+'use strict';
+
+var common = require('../common');
+var assert = require('assert');
+var cluster = require('cluster');
+var net = require('net');
+
+if (cluster.isWorker) {
+  net.createServer(function(socket) {
+    // Wait for any data, then close connection
+    socket.on('data', socket.end.bind(socket));
+  }).listen(common.PORT, common.localhostIPv4);
+} else if (cluster.isMaster) {
+
+  var connectionDone;
+  var ok;
+
+  // start worker
+  var worker = cluster.fork();
+
+  // Disconnect worker when it is ready
+  worker.once('listening', function() {
+    net.createConnection(common.PORT, common.localhostIPv4, function() {
+      var socket = this;
+      worker.disconnect();
+      setTimeout(function() {
+        socket.write('.');
+        connectionDone = true;
+      }, 1000);
+    });
+  });
+
+  // Check worker events and properties
+  worker.once('disconnect', function() {
+    assert.ok(connectionDone, 'disconnect should occur after socket close');
+    ok = true;
+  });
+
+  process.once('exit', function() {
+    assert.ok(ok);
+  });
+}