cluster: overriding inspector port

Added an option to override inspector port for workers using
`settings.inspectPort` will override default port incrementing behavior.
Also, using this option allows to set 0 port for the whole cluster.

PR-URL: https://github.com/nodejs/node/pull/14140
Fixes: https://github.com/nodejs/node/issues/8495
Fixes: https://github.com/nodejs/node/issues/12941
Refs: https://github.com/nodejs/node/pull/9659
Refs: https://github.com/nodejs/node/pull/13761
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
cornholio 2017-07-10 22:24:49 +03:00 committed by Refael Ackermann
parent 592b0ed431
commit b4300536f5
No known key found for this signature in database
GPG Key ID: CD704BD80FDDDB64
3 changed files with 251 additions and 23 deletions

View File

@ -712,6 +712,9 @@ changes:
`'ipc'` entry. When this option is provided, it overrides `silent`.
* `uid` {number} Sets the user identity of the process. (See setuid(2).)
* `gid` {number} Sets the group identity of the process. (See setgid(2).)
* `inspectPort` {number|function} Sets inspector port of worker.
Accepts number, or function that evaluates to number. By default
each worker gets port, incremented from master's `process.debugPort`.
After calling `.setupMaster()` (or `.fork()`) this settings object will contain
the settings, including the default values.

View File

@ -12,6 +12,7 @@ const cluster = new EventEmitter();
const intercom = new EventEmitter();
const SCHED_NONE = 1;
const SCHED_RR = 2;
const {isLegalPort} = require('internal/net');
module.exports = cluster;
@ -104,8 +105,23 @@ function createWorkerProcess(id, env) {
workerEnv.NODE_UNIQUE_ID = '' + id;
if (execArgv.some((arg) => arg.match(debugArgRegex))) {
execArgv.push(`--inspect-port=${process.debugPort + debugPortOffset}`);
debugPortOffset++;
let inspectPort;
if ('inspectPort' in cluster.settings) {
if (typeof cluster.settings.inspectPort === 'function')
inspectPort = cluster.settings.inspectPort();
else
inspectPort = cluster.settings.inspectPort;
if (!isLegalPort(inspectPort)) {
throw new TypeError('cluster.settings.inspectPort' +
' is invalid');
}
} else {
inspectPort = process.debugPort + debugPortOffset;
debugPortOffset++;
}
execArgv.push(`--inspect-port=${inspectPort}`);
}
return fork(cluster.settings.exec, cluster.settings.args, {

View File

@ -18,7 +18,7 @@ let offset = 0;
*/
function testRunnerMain() {
spawnMaster({
let defaultPortCase = spawnMaster({
execArgv: ['--inspect'],
workers: [{expectedPort: 9230}]
});
@ -77,42 +77,251 @@ function testRunnerMain() {
workers: [{expectedPort: port + 1, expectedHost: '::1'}]
});
}
}
// These tests check that setting inspectPort in cluster.settings
// would take effect and override port incrementing behavior
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: port + 2},
workers: [{expectedPort: port + 2}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'addTwo'},
workers: [
{expectedPort: port + 2},
{expectedPort: port + 4}
]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'string'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'null'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'bignumber'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'negativenumber'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'bignumberfunc'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 'strfunc'},
workers: [{}]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [],
clusterSettings: {inspectPort: port, execArgv: ['--inspect']},
workers: [
{expectedPort: port}
]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [`--inspect=${port}`],
clusterSettings: {inspectPort: 0},
workers: [
{expectedInitialPort: 0},
{expectedInitialPort: 0},
{expectedInitialPort: 0}
]
});
port = debuggerPort + offset++ * 5;
spawnMaster({
execArgv: [],
clusterSettings: {inspectPort: 0},
workers: [
{expectedInitialPort: 0},
{expectedInitialPort: 0},
{expectedInitialPort: 0}
]
});
defaultPortCase.then(() => {
port = debuggerPort + offset++ * 5;
defaultPortCase = spawnMaster({
execArgv: ['--inspect'],
clusterSettings: {inspectPort: port + 2},
workers: [
{expectedInitialPort: port + 2}
]
});
});
}
function masterProcessMain() {
const workers = JSON.parse(process.env.workers);
const clusterSettings = JSON.parse(process.env.clusterSettings);
let debugPort = process.debugPort;
for (const worker of workers) {
cluster.fork({
expectedPort: worker.expectedPort,
expectedHost: worker.expectedHost
}).on('exit', common.mustCall(checkExitCode));
const params = {};
if (worker.expectedPort) {
params.expectedPort = worker.expectedPort;
}
if (worker.expectedInitialPort) {
params.expectedInitialPort = worker.expectedInitialPort;
}
if (worker.expectedHost) {
params.expectedHost = worker.expectedHost;
}
if (clusterSettings) {
if (clusterSettings.inspectPort === 'addTwo') {
clusterSettings.inspectPort = common.mustCall(
() => { return debugPort += 2; },
workers.length
);
} else if (clusterSettings.inspectPort === 'string') {
clusterSettings.inspectPort = 'string';
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
} else if (clusterSettings.inspectPort === 'null') {
clusterSettings.inspectPort = null;
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
} else if (clusterSettings.inspectPort === 'bignumber') {
clusterSettings.inspectPort = 1293812;
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
} else if (clusterSettings.inspectPort === 'negativenumber') {
clusterSettings.inspectPort = -9776;
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
} else if (clusterSettings.inspectPort === 'bignumberfunc') {
clusterSettings.inspectPort = common.mustCall(
() => 123121,
workers.length
);
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
} else if (clusterSettings.inspectPort === 'strfunc') {
clusterSettings.inspectPort = common.mustCall(
() => 'invalidPort',
workers.length
);
cluster.setupMaster(clusterSettings);
assert.throws(() => {
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}, TypeError);
return;
}
cluster.setupMaster(clusterSettings);
}
cluster.fork(params).on('exit', common.mustCall(checkExitCode));
}
}
function workerProcessMain() {
const {expectedPort, expectedHost} = process.env;
const {expectedPort, expectedInitialPort, expectedHost} = process.env;
const debugOptions = process.binding('config').debugOptions;
assert.strictEqual(process.debugPort, +expectedPort);
if ('expectedPort' in process.env) {
assert.strictEqual(process.debugPort, +expectedPort);
}
if (expectedHost !== 'undefined') {
assert.strictEqual(
process.binding('config').debugOptions.host,
expectedHost
);
if ('expectedInitialPort' in process.env) {
assert.strictEqual(debugOptions.port, +expectedInitialPort);
}
if ('expectedHost' in process.env) {
assert.strictEqual(debugOptions.host, expectedHost);
}
process.exit();
}
function spawnMaster({execArgv, workers}) {
childProcess.fork(__filename, {
env: {
workers: JSON.stringify(workers),
testProcess: true
},
execArgv
}).on('exit', common.mustCall(checkExitCode));
function spawnMaster({execArgv, workers, clusterSettings = {}}) {
return new Promise((resolve) => {
childProcess.fork(__filename, {
env: {
workers: JSON.stringify(workers),
clusterSettings: JSON.stringify(clusterSettings),
testProcess: true
},
execArgv
}).on('exit', common.mustCall((code, signal) => {
checkExitCode(code, signal);
resolve();
}));
});
}
function checkExitCode(code, signal) {