diff --git a/src/transports/websocket.test.ts b/src/transports/websocket.test.ts index a794a1d..5f42a73 100644 --- a/src/transports/websocket.test.ts +++ b/src/transports/websocket.test.ts @@ -346,6 +346,38 @@ describe("WebSocket transport", () => { expect(mockServer.close).toHaveBeenCalled(); }); + it("unrefs the stop timeout so the event loop can exit", async () => { + const transport = new WebSocketTransport({ + middleware: [], + port: 9712, + }); + + const mockWss = { + clients: new Set(), + close: jest.fn((cb) => cb()), + removeAllListeners: jest.fn(), + } as any; + (transport as any).wss = mockWss; + + const mockServer = { + close: jest.fn((cb) => cb()), + } as any; + (transport as any).server = mockServer; + + const unref = jest.fn(); + const originalSetTimeout = global.setTimeout; + (global as any).setTimeout = (fn: (...args: any[]) => void, _ms?: number) => { + fn(); + return { unref } as any; + }; + + await transport.stop(); + + expect(unref).toHaveBeenCalled(); + + (global as any).setTimeout = originalSetTimeout; + }); + it("applies default timeout when none provided", () => { const transport = new WebSocketTransport({ middleware: [], diff --git a/src/transports/websocket.ts b/src/transports/websocket.ts index b0db41b..b0b56eb 100644 --- a/src/transports/websocket.ts +++ b/src/transports/websocket.ts @@ -74,7 +74,10 @@ export default class WebSocketServerTransport extends ServerTransport { socket.close(); }); // Wait for sockets to close, then hard close any remaining - await new Promise((resolve) => setTimeout(resolve, this.options.timeout)); + await new Promise((resolve) => { + // unref timer so it doesn't keep the event loop alive + setTimeout(resolve, this.options.timeout).unref(); + }); this.wss.clients.forEach((socket) => { if ([socket.OPEN, socket.CLOSING].includes((socket as any).readyState)) { socket.terminate();