Skip to content

Commit b93fc9c

Browse files
committed
src,lib: the handle keeps loop alive in cluster rr mode
1 parent 28fe494 commit b93fc9c

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

lib/internal/cluster/child.js

+22-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const { owner_symbol } = require('internal/async_hooks').symbols;
1616
const Worker = require('internal/cluster/worker');
1717
const { internal, sendHelper } = require('internal/cluster/utils');
1818
const { exitCodes: { kNoFailure } } = internalBinding('errors');
19+
const { TIMEOUT_MAX } = require('internal/timers');
20+
const { setInterval, clearInterval } = require('timers');
1921

2022
const cluster = new EventEmitter();
2123
const handles = new SafeMap();
@@ -162,6 +164,21 @@ function rr(message, { indexesKey, index }, cb) {
162164

163165
let key = message.key;
164166

167+
let fakeHandle = null;
168+
169+
function ref() {
170+
if (!fakeHandle) {
171+
fakeHandle = setInterval(noop, TIMEOUT_MAX);
172+
}
173+
}
174+
175+
function unref() {
176+
if (fakeHandle) {
177+
clearInterval(fakeHandle);
178+
fakeHandle = null;
179+
}
180+
}
181+
165182
function listen(backlog) {
166183
// TODO(bnoordhuis) Send a message to the primary that tells it to
167184
// update the backlog size. The actual backlog should probably be
@@ -177,7 +194,7 @@ function rr(message, { indexesKey, index }, cb) {
177194
// the primary.
178195
if (key === undefined)
179196
return;
180-
197+
unref();
181198
send({ act: 'close', key });
182199
handles.delete(key);
183200
removeIndexesKey(indexesKey, index);
@@ -191,12 +208,10 @@ function rr(message, { indexesKey, index }, cb) {
191208
return 0;
192209
}
193210

194-
// Faux handle. Mimics a TCPWrap with just enough fidelity to get away
195-
// with it. Fools net.Server into thinking that it's backed by a real
196-
// handle. Use a noop function for ref() and unref() because the control
197-
// channel is going to keep the worker alive anyway.
198-
const handle = { close, listen, ref: noop, unref: noop };
199-
211+
// Faux handle. net.Server is not associated with handle,
212+
// so we control its state(ref or unref) by setInterval.
213+
const handle = { close, listen, ref, unref };
214+
handle.ref();
200215
if (message.sockname) {
201216
handle.getsockname = getsockname; // TCP handles only.
202217
}
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)