Skip to content

Commit 08a6a61

Browse files
theanarkhjuanarbol
authored andcommitted
src,lib: the handle keeps loop alive in cluster rr mode
PR-URL: #46161 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
1 parent 3ce39bb commit 08a6a61

4 files changed

+88
-7
lines changed

lib/internal/cluster/child.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const EventEmitter = require('events');
1515
const { owner_symbol } = require('internal/async_hooks').symbols;
1616
const Worker = require('internal/cluster/worker');
1717
const { internal, sendHelper } = require('internal/cluster/utils');
18+
const { TIMEOUT_MAX } = require('internal/timers');
19+
const { setInterval, clearInterval } = require('timers');
20+
1821
const cluster = new EventEmitter();
1922
const handles = new SafeMap();
2023
const indexes = new SafeMap();
@@ -160,6 +163,21 @@ function rr(message, { indexesKey, index }, cb) {
160163

161164
let key = message.key;
162165

166+
let fakeHandle = null;
167+
168+
function ref() {
169+
if (!fakeHandle) {
170+
fakeHandle = setInterval(noop, TIMEOUT_MAX);
171+
}
172+
}
173+
174+
function unref() {
175+
if (fakeHandle) {
176+
clearInterval(fakeHandle);
177+
fakeHandle = null;
178+
}
179+
}
180+
163181
function listen(backlog) {
164182
// TODO(bnoordhuis) Send a message to the primary that tells it to
165183
// update the backlog size. The actual backlog should probably be
@@ -175,7 +193,11 @@ function rr(message, { indexesKey, index }, cb) {
175193
// the primary.
176194
if (key === undefined)
177195
return;
178-
196+
unref();
197+
// If the handle is the last handle in process,
198+
// the parent process will delete the handle when worker process exits.
199+
// So it is ok if the close message get lost.
200+
// See the comments of https://github.com/nodejs/node/pull/46161
179201
send({ act: 'close', key });
180202
handles.delete(key);
181203
removeIndexesKey(indexesKey, index);
@@ -189,12 +211,10 @@ function rr(message, { indexesKey, index }, cb) {
189211
return 0;
190212
}
191213

192-
// Faux handle. Mimics a TCPWrap with just enough fidelity to get away
193-
// with it. Fools net.Server into thinking that it's backed by a real
194-
// handle. Use a noop function for ref() and unref() because the control
195-
// channel is going to keep the worker alive anyway.
196-
const handle = { close, listen, ref: noop, unref: noop };
197-
214+
// Faux handle. net.Server is not associated with handle,
215+
// so we control its state(ref or unref) by setInterval.
216+
const handle = { close, listen, ref, unref };
217+
handle.ref();
198218
if (message.sockname) {
199219
handle.getsockname = getsockname; // TCP handles only.
200220
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
7+
cluster.schedulingPolicy = cluster.SCHED_RR;
8+
9+
if (cluster.isPrimary) {
10+
const worker = cluster.fork();
11+
worker.on('exit', common.mustCall());
12+
} else {
13+
const server = net.createServer(common.mustNotCall());
14+
server.listen(0, common.mustCall(() => {
15+
process.channel.unref();
16+
server.close();
17+
}));
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
const assert = require('assert');
7+
8+
cluster.schedulingPolicy = cluster.SCHED_RR;
9+
10+
if (cluster.isPrimary) {
11+
let exited = false;
12+
const worker = cluster.fork();
13+
worker.on('exit', () => {
14+
exited = true;
15+
});
16+
setTimeout(() => {
17+
assert.ok(!exited);
18+
worker.kill();
19+
}, 3000);
20+
} else {
21+
const server = net.createServer(common.mustNotCall());
22+
server.listen(0, common.mustCall(() => process.channel.unref()));
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
7+
cluster.schedulingPolicy = cluster.SCHED_RR;
8+
9+
if (cluster.isPrimary) {
10+
const worker = cluster.fork();
11+
worker.on('exit', common.mustCall());
12+
} else {
13+
const server = net.createServer(common.mustNotCall());
14+
server.listen(0, common.mustCall(() => {
15+
server.ref();
16+
server.unref();
17+
process.channel.unref();
18+
}));
19+
server.unref();
20+
}

0 commit comments

Comments
 (0)