fix(server): make the null-socket guard registration idempotent

registerPostgresNullSocketGuard() added one uncaughtException listener
on every call. A caller that runs it many times in one process, such
as a test suite that calls startServer() repeatedly, crossed Node's
default listener-count warning threshold. Skip the process.on call
when the guard's own listener function is already registered.

Also extend the unrelated-crash fixture scenario to assert the child
process reports the error message and the stack, and add a test that
proves a second registration adds no second listener.

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Priya RamanandPaperclip committed 2026-09-04 01:14:47 +00:00
1 parent 24691cf54c
commit cba31a8505
2 files changed
+19 -2

No files matched your search

@@ -152,6 +152,13 @@ describe("registerPostgresNullSocketGuard", () => {
registerPostgresNullSocketGuard({ POSTGRES_NULL_SOCKET_GUARD_ENABLED: "false" });
expect(process.listenerCount("uncaughtException")).toBe(before);
});
it("adds one listener however many times it runs", () => {
const before = process.listenerCount("uncaughtException");
registerPostgresNullSocketGuard({});
registerPostgresNullSocketGuard({});
expect(process.listenerCount("uncaughtException")).toBe(before + 1);
});
});
describe("handlePostgresNullSocketGuardException", () => {
@@ -257,10 +264,16 @@ describe("the driver crash sequence, reproduced against a fake wire server", ()
expect(result.code).toBe(0);
}, 20_000);
it("a non-matching uncaught exception still ends the process", async () => {
it("a non-matching uncaught exception still ends the process and reports its cause", async () => {
const result = await runFixture("unrelated-crash");
expect(messageTypes(result)).not.toContain("unexpected-survival");
expect(result.code).toBe(1);
// The logger writes the fatal record to standard output; Node's own
// default handler would have used standard error, but the guard
// replaces that handler for every uncaught exception, so this is the
// only place the message and the stack can appear.
expect(result.stdout).toContain("an unrelated failure the guard must not swallow");
expect(result.stdout).toContain("at Immediate");
}, 20_000);
});
+5 -1
View File
@@ -97,9 +97,13 @@ export function handlePostgresNullSocketGuardException(error: unknown): void {
/**
* Registers the guard's `uncaughtException` listener, unless an operator
* disables it with `POSTGRES_NULL_SOCKET_GUARD_ENABLED=false` (or `0`).
* Call this once, early, from the server entry point.
* Call this once, early, from the server entry point. This function is
* idempotent: a repeat call adds no second listener, so a caller that runs
* many times in one process (a test suite that calls `startServer()`
* repeatedly) never exceeds Node's default listener-count warning.
*/
export function registerPostgresNullSocketGuard(env: NodeJS.ProcessEnv = process.env): void {
if (!isGuardEnabled(env)) return;
if (process.listeners("uncaughtException").includes(handlePostgresNullSocketGuardException)) return;
process.on("uncaughtException", handlePostgresNullSocketGuardException);
}