diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 7ab4d33dbd9ca8..016fdf6c185c68 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -722,6 +722,8 @@ changes: This can be a number, or a function that takes no arguments and returns a number. By default each worker gets its own port, incremented from the master's `process.debugPort`. + * `windowsHide` {boolean} Hide the forked processes console window that would + normally be created on Windows systems. **Default:** `false` After calling `.setupMaster()` (or `.fork()`) this settings object will contain the settings, including the default values. diff --git a/lib/internal/cluster/master.js b/lib/internal/cluster/master.js index f3d2e30a5b73f0..408b31c2b77805 100644 --- a/lib/internal/cluster/master.js +++ b/lib/internal/cluster/master.js @@ -127,6 +127,7 @@ function createWorkerProcess(id, env) { return fork(cluster.settings.exec, cluster.settings.args, { env: workerEnv, silent: cluster.settings.silent, + windowsHide: cluster.settings.windowsHide, execArgv: execArgv, stdio: cluster.settings.stdio, gid: cluster.settings.gid, diff --git a/test/parallel/test-cluster-fork-windowsHide.js b/test/parallel/test-cluster-fork-windowsHide.js new file mode 100644 index 00000000000000..eb6166858d4582 --- /dev/null +++ b/test/parallel/test-cluster-fork-windowsHide.js @@ -0,0 +1,77 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); + +let patchedFork = child_process.fork; +child_process.fork = (...args) => patchedFork.apply(this, args); +const cluster = require('cluster'); + +if (!process.argv[2]) { + const master = child_process.spawn( + process.argv[0], + [process.argv[1], '--cluster'], + { detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] }); + + const messageHandlers = { + windowsHide: common.mustCall((msg) => { + assert.strictEqual(msg.value, true); + }), + workerOnline: common.mustCall((msg) => { + }), + mainWindowHandle: common.mustCall((msg) => { + assert.ok(/0\s*/.test(msg.value)); + }), + workerExit: common.mustCall((msg) => { + assert.strictEqual(msg.code, 0); + assert.strictEqual(msg.signal, null); + }) + }; + + master.on('message', (msg) => { + const handler = messageHandlers[msg.type]; + assert.ok(handler); + handler(msg); + }); + + master.on('exit', common.mustCall((code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); + })); + +} else if (cluster.isMaster) { + const originalFork = patchedFork; + patchedFork = common.mustCall((...args) => { + process.send({ type: 'windowsHide', value: args[2].windowsHide }); + return originalFork.apply(this, args); + }); + + cluster.setupMaster({ + silient: true, + windowsHide: true + }); + + const worker = cluster.fork(); + worker.on('exit', (code, signal) => { + process.send({ type: 'workerExit', code: code, signal: signal }); + }); + + worker.on('online', (msg) => { + process.send({ type: 'workerOnline' }); + + let output = '0'; + if (process.platform === 'win32') + output = child_process.execSync( + 'powershell -NoProfile -c ' + + `"(Get-Process -Id ${worker.process.pid}).MainWindowHandle"`, + { windowsHide: true, encoding: 'utf8' }); + + process.send({ type: 'mainWindowHandle', value: output }); + worker.send('shutdown'); + }); + +} else { + cluster.worker.on('message', (msg) => { + cluster.worker.disconnect(); + }); +}