mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 11:27:39 +00:00
fix(browser): handle EADDRINUSE with automatic port fallback
When the Chrome extension relay server fails to bind due to port conflict (EADDRINUSE), automatically try alternative ports in the dynamic range (49152-65535) instead of failing immediately. This resolves issues where stale processes hold onto port 18792 after gateway restarts or crashes. Fixes potential issues related to #8926, #13867, #17584
This commit is contained in:
@@ -6,6 +6,9 @@ import { createServer } from "node:http";
|
|||||||
import WebSocket, { WebSocketServer } from "ws";
|
import WebSocket, { WebSocketServer } from "ws";
|
||||||
import { isLoopbackAddress, isLoopbackHost } from "../gateway/net.js";
|
import { isLoopbackAddress, isLoopbackHost } from "../gateway/net.js";
|
||||||
import { rawDataToString } from "../infra/ws.js";
|
import { rawDataToString } from "../infra/ws.js";
|
||||||
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||||
|
|
||||||
|
const logService = createSubsystemLogger("browser").child("relay");
|
||||||
|
|
||||||
type CdpCommand = {
|
type CdpCommand = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -703,10 +706,37 @@ export async function ensureChromeExtensionRelayServer(opts: {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
// Try to bind to the requested port, with automatic fallback on EADDRINUSE.
|
||||||
server.listen(info.port, info.host, () => resolve());
|
let boundPort = info.port;
|
||||||
server.once("error", reject);
|
const maxRetries = 10;
|
||||||
});
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
const onError = (err: Error) => {
|
||||||
|
server.removeListener("listening", resolve);
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
const onListening = () => {
|
||||||
|
server.removeListener("error", onError);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
server.once("error", onError);
|
||||||
|
server.once("listening", onListening);
|
||||||
|
server.listen(boundPort, info.host);
|
||||||
|
});
|
||||||
|
// Successfully bound
|
||||||
|
break;
|
||||||
|
} catch (err) {
|
||||||
|
const isAddrInUse = (err as { code?: string }).code === "EADDRINUSE";
|
||||||
|
if (isAddrInUse && attempt < maxRetries - 1) {
|
||||||
|
// Try a random port in the dynamic range (49152-65535)
|
||||||
|
boundPort = Math.floor(Math.random() * (65535 - 49152 + 1)) + 49152;
|
||||||
|
logService.warn(`Port ${info.port} is in use, trying alternative port ${boundPort}...`);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const addr = server.address() as AddressInfo | null;
|
const addr = server.address() as AddressInfo | null;
|
||||||
const port = addr?.port ?? info.port;
|
const port = addr?.port ?? info.port;
|
||||||
|
|||||||
Reference in New Issue
Block a user