From 35854ae29d771279cec55c233fa4194f0ca19082 Mon Sep 17 00:00:00 2001 From: Oleg Elifantiev Date: Tue, 2 Jun 2015 23:23:31 +0300 Subject: [PATCH] cluster: wait for all servers closing before disconnect Fix for iojs/io,js#1305 Before this, cluster bahaves not the way it is docummented Then disconnect is triggered, worker must wait for every server is closed before doing disconnect actually. See test case and discussion in the above mentioned issue --- lib/cluster.js | 18 +++++- .../test-cluster-worker-wait-server-close.js | 63 +++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-cluster-worker-wait-server-close.js diff --git a/lib/cluster.js b/lib/cluster.js index 08230ad4aa882c..39fed1c71a06ba 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -625,12 +625,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 index 00000000000000..a3d29cec1715cd --- /dev/null +++ b/test/parallel/test-cluster-worker-wait-server-close.js @@ -0,0 +1,63 @@ +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 checks = { + disconnectedOnClientsEnd: false, + workerDied: false + }; + + // helper function to check if a process is alive + var alive = function(pid) { + try { + process.kill(pid, 0); + return true; + } catch (e) { + return false; + } + }; + + // 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; + setTimeout(function() { + worker.disconnect(); + setTimeout(function() { + socket.write('.'); + connectionDone = true; + }, 1000); + }, 1000); + }); + }); + + // Check worker events and properties + worker.once('disconnect', function() { + checks.disconnectedOnClientsEnd = connectionDone; + }); + + // Check that the worker died + worker.once('exit', function() { + checks.workerDied = !alive(worker.process.pid); + process.nextTick(function() { + process.exit(0); + }); + }); + + process.once('exit', function() { + assert.ok(checks.disconnectedOnClientsEnd, 'The worker disconnected before all clients are ended'); + assert.ok(checks.workerDied, 'The worker did not die'); + }); +}