Skip to content

Commit 0ac7668

Browse files
fix(ports): enforce pre-start port clearance across suites\n\n- start-all: ensurePortFree before all consumers-react & expose servers; Next binds to 127.0.0.1\n- ssr start-exposes/shells: ensurePortFree before serve; kill any listeners via lsof/fuser\n- add diagnostics and stronger kill loops
1 parent 5893f30 commit 0ac7668

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

federated-css-react-ssr/scripts/start-exposes.cjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const { spawn } = require('node:child_process');
22
const path = require('node:path');
33
const waitOn = require('wait-on');
44
const kill = require('kill-port');
5+
const { execSync } = require('node:child_process');
56

67
const root = path.resolve(__dirname, '..');
78

@@ -17,6 +18,28 @@ async function killPort(port) {
1718
}
1819
}
1920

21+
const delay = ms => new Promise(r => setTimeout(r, ms));
22+
function isPortInUse(port) {
23+
try {
24+
const out = execSync(`lsof -nPiTCP -sTCP:LISTEN | grep :${port}\\>`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
25+
return out.trim().length > 0;
26+
} catch {
27+
return false;
28+
}
29+
}
30+
function forceKillPort(port) {
31+
try { execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'ignore' }); } catch {}
32+
try { execSync(`fuser -k ${port}/tcp`, { stdio: 'ignore' }); } catch {}
33+
}
34+
async function ensurePortFree(port, timeoutMs = 15000) {
35+
const start = Date.now();
36+
while (Date.now() - start < timeoutMs) {
37+
if (!isPortInUse(port)) return;
38+
forceKillPort(port);
39+
await delay(500);
40+
}
41+
}
42+
2043
async function exec(cmd, args, opts = {}) {
2144
return new Promise((resolve, reject) => {
2245
const p = run(cmd, args, opts);
@@ -54,6 +77,8 @@ async function main() {
5477
const cwd = path.join('expose-apps', dir);
5578
console.log(`[exposes] building ${dir}...`);
5679
await exec('pnpm', ['-C', cwd, 'run', 'build']);
80+
console.log(`[exposes] ensuring port ${port} is free for ${dir}...`);
81+
await ensurePortFree(port, 20000);
5782
console.log(`[exposes] serving ${dir} on ${port}...`);
5883
const p = run('pnpm', ['-C', cwd, 'run', 'serve']);
5984
procs.push(p);

federated-css-react-ssr/scripts/start-shells.cjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const { spawn } = require('node:child_process');
22
const path = require('node:path');
33
const waitOn = require('wait-on');
44
const kill = require('kill-port');
5+
const { execSync } = require('node:child_process');
56

67
const root = path.resolve(__dirname, '..');
78

@@ -17,6 +18,28 @@ async function killPort(port) {
1718
}
1819
}
1920

21+
const delay = ms => new Promise(r => setTimeout(r, ms));
22+
function isPortInUse(port) {
23+
try {
24+
const out = execSync(`lsof -nPiTCP -sTCP:LISTEN | grep :${port}\\>`, { stdio: ['ignore', 'pipe', 'ignore'] }).toString();
25+
return out.trim().length > 0;
26+
} catch {
27+
return false;
28+
}
29+
}
30+
function forceKillPort(port) {
31+
try { execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'ignore' }); } catch {}
32+
try { execSync(`fuser -k ${port}/tcp`, { stdio: 'ignore' }); } catch {}
33+
}
34+
async function ensurePortFree(port, timeoutMs = 15000) {
35+
const start = Date.now();
36+
while (Date.now() - start < timeoutMs) {
37+
if (!isPortInUse(port)) return;
38+
forceKillPort(port);
39+
await delay(500);
40+
}
41+
}
42+
2043
async function exec(cmd, args, opts = {}) {
2144
return new Promise((resolve, reject) => {
2245
const p = run(cmd, args, opts);
@@ -54,6 +77,8 @@ async function main() {
5477
console.log(`[shells] building ${dir}...`);
5578
await exec('pnpm', ['-C', cwd, 'run', 'build']);
5679

80+
console.log(`[shells] ensuring port ${port} is free for ${dir}...`);
81+
await ensurePortFree(port, 20000);
5782
console.log(`[shells] starting ${dir} on port ${port}...`);
5883
const p = run('pnpm', ['-C', cwd, 'run', 'serve']);
5984
procs.push(p);

federated-css/scripts/start-all.cjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ async function main() {
129129
const buildProc = run('pnpm', ['-C', cwd, 'run', 'build']);
130130
buildProc.on('exit', code => (code === 0 ? res() : rej(new Error(`build ${dir} failed`))));
131131
});
132+
console.log(`[federated-css] ensuring port ${port} is free for consumers-react ${dir}...`);
133+
await ensurePortFree(port, 20000);
132134
const serveProc = run('pnpm', ['-C', cwd, 'run', 'serve']);
133135
procs.push(serveProc);
134136

@@ -172,6 +174,8 @@ async function main() {
172174
const dir = dirMap[port];
173175
if (!dir) continue;
174176
const cwd = path.join('expose-remotes', dir);
177+
console.log(`[federated-css] ensuring port ${port} is free for expose ${dir}...`);
178+
await ensurePortFree(port, 20000);
175179
const p = run('pnpm', ['-C', cwd, 'run', 'serve']);
176180
procs.push(p);
177181
const exposeResources = [
@@ -205,7 +209,7 @@ async function main() {
205209
console.log(`[federated-css] ensuring port ${port} is free for ${label}...`);
206210
await ensurePortFree(port, 20000);
207211
console.log(`[federated-css] starting ${label} with next start...`);
208-
const proc = run('pnpm', ['-C', cwd, 'exec', 'next', 'start', '-p', String(port)]);
212+
const proc = run('pnpm', ['-C', cwd, 'exec', 'next', 'start', '-H', '127.0.0.1', '-p', String(port)]);
209213
procs.push(proc);
210214

211215
try {

0 commit comments

Comments
 (0)