fix(server-runtime): ignore duplicate websocket listener (#1829)

This commit is contained in:
Neko
2026-05-14 01:53:41 +08:00
committed by GitHub
parent 5ab8b0e33e
commit 541b9fa53c
3 changed files with 26 additions and 0 deletions
@@ -90,6 +90,19 @@ describe('createServer', async () => {
await retryStart
})
it('treats EADDRINUSE as an existing listener instead of failing startup', async () => {
const server = createServer({ hostname: '127.0.0.1', port: 6121 })
const startTask = server.start()
const error = new Error('listen EADDRINUSE: address already in use 127.0.0.1:6121') as NodeJS.ErrnoException
error.code = 'EADDRINUSE'
serveMocks.rejectServe(error)
await expect(startTask).resolves.toBeUndefined()
expect(serveMocks.disposeCall).toHaveBeenCalledTimes(1)
expect(serveMocks.closeCall).toHaveBeenCalledWith(true)
})
it('merges nested config updates instead of replacing sibling logger settings', async () => {
const server = createServer({
hostname: '127.0.0.1',
@@ -32,6 +32,13 @@ export interface Server {
updateConfig: (newOptions: ServerOptions) => void
}
function isAddressInUseError(error: unknown) {
return typeof error === 'object'
&& error !== null
&& 'code' in error
&& (error as NodeJS.ErrnoException).code === 'EADDRINUSE'
}
/**
* Collects local IP addresses that can be used to reach the server from the LAN.
*
@@ -189,6 +196,10 @@ export function createServer(opts?: ServerOptions): Server {
serverInstance = null
h3App.dispose()
await instance.close(true).catch(() => {})
if (isAddressInUseError(error)) {
log.withError(error).warn('WebSocket server port already in use, assuming an existing listener is available')
return
}
log.withError(error).error('failed to start WebSocket server')
throw error
}