From ed8f6a3c0e25f42aacf8e4d5f3090b477675495b Mon Sep 17 00:00:00 2001 From: islandryu Date: Wed, 5 Aug 2026 00:41:17 +0900 Subject: [PATCH 1/2] cluster: report EADDRINUSE when a worker listens twice on the same port Fixes: https://github.com/nodejs/node/issues/64869 Signed-off-by: islandryu --- lib/internal/cluster/primary.js | 12 +++++++- .../test-cluster-listen-twice-same-port.js | 29 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/sequential/test-cluster-listen-twice-same-port.js diff --git a/lib/internal/cluster/primary.js b/lib/internal/cluster/primary.js index 6ab845c6d122..169f3ea60825 100644 --- a/lib/internal/cluster/primary.js +++ b/lib/internal/cluster/primary.js @@ -16,6 +16,7 @@ const { } = require('internal/errors'); const assert = require('internal/assert'); +const { UV_EADDRINUSE } = internalBinding('uv'); const { fork } = require('child_process'); const path = require('path'); const EventEmitter = require('events'); @@ -274,7 +275,16 @@ function queryServer(worker, message) { `${message.fd}` + (message.port === 0 ? `:${message.index}` : ''); const cachedHandle = handles.get(key); let handle; - if (cachedHandle && !cachedHandle.has(worker)) { + if (cachedHandle) { + if (cachedHandle.has(worker)) { + send(worker, { + errno: UV_EADDRINUSE, + key, + ack: message.seq, + data: cachedHandle.data, + }); + return; + } handle = cachedHandle; } diff --git a/test/sequential/test-cluster-listen-twice-same-port.js b/test/sequential/test-cluster-listen-twice-same-port.js new file mode 100644 index 000000000000..d522fe363f21 --- /dev/null +++ b/test/sequential/test-cluster-listen-twice-same-port.js @@ -0,0 +1,29 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const cluster = require('cluster'); +const net = require('net'); + +if (cluster.isPrimary) { + cluster.fork().on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); + return; +} + +function listen() { + return new Promise((resolve, reject) => { + const server = net.createServer(); + server.once('error', reject); + server.once('listening', () => resolve(server)); + server.listen({ host: '127.0.0.1', port: common.PORT }); + }); +} + +(async () => { + const server1 = await listen(); + await assert.rejects(listen(), { code: 'EADDRINUSE' }); + await new Promise((resolve) => server1.close(resolve)); + cluster.worker.disconnect(); +})().then(common.mustCall()); From d095f6e42fc5941753090f2a92ce5657cc1f8d56 Mon Sep 17 00:00:00 2001 From: islandryu Date: Sun, 23 Aug 2026 16:39:55 +0900 Subject: [PATCH 2/2] test: cover SCHED_NONE and SCHED_RR in cluster listen-twice-same-port test --- .../test-cluster-listen-twice-same-port.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/sequential/test-cluster-listen-twice-same-port.js b/test/sequential/test-cluster-listen-twice-same-port.js index d522fe363f21..0d744dcc1278 100644 --- a/test/sequential/test-cluster-listen-twice-same-port.js +++ b/test/sequential/test-cluster-listen-twice-same-port.js @@ -5,6 +5,29 @@ const assert = require('assert'); const cluster = require('cluster'); const net = require('net'); +if (process.argv[2] === undefined) { + const { fork } = require('child_process'); + + function run(policy) { + return new Promise((resolve) => { + const child = fork(__filename, [policy]); + child.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + resolve(); + })); + }); + } + + (async () => { + await run('none'); + await run('rr'); + })().then(common.mustCall()); + return; +} + +cluster.schedulingPolicy = + process.argv[2] === 'rr' ? cluster.SCHED_RR : cluster.SCHED_NONE; + if (cluster.isPrimary) { cluster.fork().on('exit', common.mustCall((code) => { assert.strictEqual(code, 0);