Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 94d337e

Browse files
AndreasMadsenisaacs
authored andcommitted
cluster: kill workers when master dies
This patch will kill the worker once it has lost its connection with the parent. However if the worker are doing a suicide, other measures will be used.
1 parent d927fbc commit 94d337e

File tree

2 files changed

+111
-37
lines changed

2 files changed

+111
-37
lines changed

lib/cluster.js

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,6 @@ cluster.setupMaster = function(options) {
109109
silent: options.silent || false
110110
};
111111

112-
// Kill workers when a uncaught exception is received
113-
process.on('uncaughtException', function(err) {
114-
// Did the user install a listener? If so, it overrides this one.
115-
if (process.listeners('uncaughtException').length > 1) return;
116-
117-
// Output the error stack, and create on if non exist
118-
if (!(err instanceof Error)) {
119-
err = new Error(err);
120-
}
121-
console.error(err.stack);
122-
123-
// quick destroy cluster
124-
quickDestroyCluster();
125-
// when done exit process with error code: 1
126-
process.exit(1);
127-
});
128-
129112
// emit setup event
130113
cluster.emit('setup');
131114
};
@@ -401,17 +384,10 @@ Worker.prototype.destroy = function() {
401384
process.exit(0);
402385
});
403386

404-
// When master do a quickDestroy the channel is not necesarily closed
405-
// at the point this function runs. For that reason we need to keep
406-
// checking that the channel is still open, until a actually callback
407-
// from the master is resicved. Also we can't do a timeout and then
408-
// just kill, since we don't know if the quickDestroy function was called.
409-
setInterval(function() {
410-
if (!self.process.connected) {
411-
process.exit(0);
412-
}
413-
}, 200);
414-
387+
// When channel is closed, terminate the process
388+
this.process.once('disconnect', function() {
389+
process.exit(0);
390+
});
415391
} else {
416392
process.exit(0);
417393
}
@@ -509,20 +485,20 @@ cluster.disconnect = function(callback) {
509485
progress.check();
510486
};
511487

512-
// Sync way to quickly kill all cluster workers
513-
// However the workers may not die instantly
514-
function quickDestroyCluster() {
515-
eachWorker(function(worker) {
516-
worker.process.disconnect();
517-
worker.process.kill();
518-
});
519-
}
520-
521488
// Internal function. Called from src/node.js when worker process starts.
522489
cluster._setupWorker = function() {
490+
523491
// Get worker class
524492
var worker = cluster.worker = new Worker();
525493

494+
// when the worker is disconnected from parent accidently
495+
// we will terminate the worker
496+
process.once('disconnect', function() {
497+
if (worker.suicide !== true) {
498+
process.exit(0);
499+
}
500+
});
501+
526502
// Tell master that the worker is online
527503
worker.state = 'online';
528504
sendInternalMessage(worker, { cmd: 'online' });
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
23+
var common = require('../common');
24+
var assert = require('assert');
25+
var cluster = require('cluster');
26+
27+
if (cluster.isWorker) {
28+
29+
// keep the worker alive
30+
var http = require('http');
31+
http.Server().listen(common.PORT, '127.0.0.1');
32+
33+
} else if (process.argv[2] === 'cluster') {
34+
35+
var worker = cluster.fork();
36+
37+
// send PID info to testcase process
38+
process.send({
39+
pid: worker.process.pid
40+
});
41+
42+
// terminate the cluster process
43+
worker.once('listening', function() {
44+
setTimeout(function() {
45+
process.exit(0);
46+
}, 1000);
47+
});
48+
49+
} else {
50+
51+
// This is the testcase
52+
var fork = require('child_process').fork;
53+
54+
// is process alive helper
55+
var isAlive = function(pid) {
56+
try {
57+
//this will throw an error if the process is dead
58+
process.kill(pid, 0);
59+
60+
return true;
61+
} catch (e) {
62+
return false;
63+
}
64+
};
65+
66+
// Spawn a cluster process
67+
var master = fork(process.argv[1], ['cluster']);
68+
69+
// get pid info
70+
var pid = null;
71+
master.once('message', function(data) {
72+
pid = data.pid;
73+
});
74+
75+
// When master is dead
76+
var alive = true;
77+
master.on('exit', function(code) {
78+
79+
// make sure that the master died by purpose
80+
assert.equal(code, 0);
81+
82+
// check worker process status
83+
setTimeout(function() {
84+
alive = isAlive(pid);
85+
}, 200);
86+
});
87+
88+
process.once('exit', function() {
89+
// cleanup: kill the worker if alive
90+
if (alive) {
91+
process.kill(pid);
92+
}
93+
94+
assert.equal(typeof pid, 'number', 'did not get worker pid info');
95+
assert.equal(alive, false, 'worker was alive after master died');
96+
});
97+
98+
}

0 commit comments

Comments
 (0)