Skip to content

Commit

Permalink
src,lib: the handle keeps loop alive in cluster rr mode
Browse files Browse the repository at this point in the history
  • Loading branch information
theanarkh committed Jan 11, 2023
1 parent 28fe494 commit b93fc9c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 7 deletions.
29 changes: 22 additions & 7 deletions lib/internal/cluster/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const { owner_symbol } = require('internal/async_hooks').symbols;
const Worker = require('internal/cluster/worker');
const { internal, sendHelper } = require('internal/cluster/utils');
const { exitCodes: { kNoFailure } } = internalBinding('errors');
const { TIMEOUT_MAX } = require('internal/timers');
const { setInterval, clearInterval } = require('timers');

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

let key = message.key;

let fakeHandle = null;

function ref() {
if (!fakeHandle) {
fakeHandle = setInterval(noop, TIMEOUT_MAX);
}
}

function unref() {
if (fakeHandle) {
clearInterval(fakeHandle);
fakeHandle = null;
}
}

function listen(backlog) {
// TODO(bnoordhuis) Send a message to the primary that tells it to
// update the backlog size. The actual backlog should probably be
Expand All @@ -177,7 +194,7 @@ function rr(message, { indexesKey, index }, cb) {
// the primary.
if (key === undefined)
return;

unref();
send({ act: 'close', key });
handles.delete(key);
removeIndexesKey(indexesKey, index);
Expand All @@ -191,12 +208,10 @@ function rr(message, { indexesKey, index }, cb) {
return 0;
}

// Faux handle. Mimics a TCPWrap with just enough fidelity to get away
// with it. Fools net.Server into thinking that it's backed by a real
// handle. Use a noop function for ref() and unref() because the control
// channel is going to keep the worker alive anyway.
const handle = { close, listen, ref: noop, unref: noop };

// Faux handle. net.Server is not associated with handle,
// so we control its state(ref or unref) by setInterval.
const handle = { close, listen, ref, unref };
handle.ref();
if (message.sockname) {
handle.getsockname = getsockname; // TCP handles only.
}
Expand Down
23 changes: 23 additions & 0 deletions test/parallel/test-cluster-rr-handle-keep-loop-alive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';

const common = require('../common');
const cluster = require('cluster');
const net = require('net');
const assert = require('assert');

cluster.schedulingPolicy = cluster.SCHED_RR;

if (cluster.isPrimary) {
let exited = false;
const worker = cluster.fork();
worker.on('exit', () => {
exited = true;
});
setTimeout(() => {
assert.ok(!exited);
worker.kill();
}, 3000);
} else {
const server = net.createServer(common.mustNotCall());
server.listen(0, common.mustCall(() => process.channel.unref()));
}
20 changes: 20 additions & 0 deletions test/parallel/test-cluster-rr-handle-ref-unref.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const common = require('../common');
const cluster = require('cluster');
const net = require('net');

cluster.schedulingPolicy = cluster.SCHED_RR;

if (cluster.isPrimary) {
const worker = cluster.fork();
worker.on('exit', common.mustCall());
} else {
const server = net.createServer(common.mustNotCall());
server.listen(0, common.mustCall(() => {
server.ref();
server.unref();
process.channel.unref();
}));
server.unref();
}

0 comments on commit b93fc9c

Please sign in to comment.