diff --git a/src/graceful-helpers.ts b/src/graceful-helpers.ts new file mode 100644 index 000000000..ce8bbb3b8 --- /dev/null +++ b/src/graceful-helpers.ts @@ -0,0 +1,22 @@ +import http from "node:http"; +import type { Socket } from "node:net"; +import type { TLSSocket } from "node:tls"; + +export const hasResponse = ( + socket: Socket, +): socket is typeof socket & { _httpMessage: http.ServerResponse } => + "_httpMessage" in socket && + socket._httpMessage instanceof http.ServerResponse; + +export const hasHttpServer = ( + socket: Socket, +): socket is typeof socket & { server: http.Server } => + "server" in socket && socket.server instanceof http.Server; + +export const isEncrypted = (socket: Socket): socket is TLSSocket => + "encrypted" in socket && + typeof socket.encrypted === "boolean" && + socket.encrypted; + +export const weAreClosed: http.RequestListener = ({}, res) => + void (!res.headersSent && res.setHeader("connection", "close")); diff --git a/src/graceful-shutdown.ts b/src/graceful-shutdown.ts index 2a779d273..4386df70e 100644 --- a/src/graceful-shutdown.ts +++ b/src/graceful-shutdown.ts @@ -2,27 +2,13 @@ import http from "node:http"; import https from "node:https"; import { setInterval } from "node:timers/promises"; import type { Socket } from "node:net"; -import type { TLSSocket } from "node:tls"; import type { ActualLogger } from "./logger-helpers"; - -const hasResponse = ( - socket: Socket, -): socket is typeof socket & { _httpMessage: http.ServerResponse } => - "_httpMessage" in socket && - socket._httpMessage instanceof http.ServerResponse; - -const hasHttpServer = ( - socket: Socket, -): socket is typeof socket & { server: http.Server } => - "server" in socket && socket.server instanceof http.Server; - -const isEncrypted = (socket: Socket): socket is TLSSocket => - "encrypted" in socket && - typeof socket.encrypted === "boolean" && - socket.encrypted; - -const weAreClosed: http.RequestListener = ({}, res) => - void (!res.headersSent && res.setHeader("connection", "close")); +import { + hasHttpServer, + hasResponse, + isEncrypted, + weAreClosed, +} from "./graceful-helpers"; export const monitor = ({ server, @@ -33,9 +19,15 @@ export const monitor = ({ timeout?: number; logger?: ActualLogger; }) => { + let pending: Promise | undefined; const sockets = new Set(); + const destroy = (socket: Socket) => void sockets.delete(socket.destroy()); - let pending: Promise | undefined; + const disconnect = (socket: Socket) => + void (hasResponse(socket) + ? !socket._httpMessage.headersSent && + socket._httpMessage.setHeader("connection", "close") + : destroy(socket)); const watch = (socket: Socket) => void (pending @@ -51,14 +43,6 @@ export const monitor = ({ void server.close((error) => (error ? reject(error) : resolve())), ); - const destroy = (socket: Socket) => void sockets.delete(socket.destroy()); - - const disconnect = (socket: Socket) => - void (hasResponse(socket) - ? !socket._httpMessage.headersSent && - socket._httpMessage.setHeader("connection", "close") - : destroy(socket)); - const workflow = async () => { server.on("request", weAreClosed); logger?.info("Graceful shutdown", { sockets: sockets.size, timeout });