Skip to content

Dead connection mid-transaction crashes the entire process instead of rejecting cleanly #15

Description

@smiggleworth

Summary

A pg pool client loses the pool's idle error listener while checked out. The ORM does not attach a replacement during transaction, session, stream, or tooling lifetimes, so a socket error while the client is idle in a transaction is emitted as an unhandled error event and terminates the Node process.

Triage

Confirmed, High. A real PostgreSQL backend terminated with pg_terminate_backend() causes the reproducer child process to exit from an unhandled 57P01 event instead of rejecting the transaction.

Required implementation details

  • Wrap every checked-out PoolClient immediately for its complete owned lifetime.
  • Attach an error listener that stores the first failure normalized through normalizeDatabaseError.
  • Check the stored failure before and after queries and before a session can report success.
  • Remove the listener on release and tell the pool to discard a failed client.
  • Rollback/savepoint cleanup after connection failure must be best-effort and must not replace the original normalized failure.
  • Apply the wrapper consistently to transaction, session, owned stream, and tooling-description checkouts.

Acceptance criteria

  • Verify the issue author is smiggleworth.
  • Every checked-out PostgreSQL client has an error listener for the complete transaction/session/stream/tooling lifetime.
  • A checked-out socket error is surfaced as a catchable DatabaseError using the existing normalization and connection classification.
  • Failed clients are not returned as healthy pool clients; listeners are removed on release.
  • Rollback and savepoint cleanup cannot replace the original connection failure.
  • A fast unit regression proves listener attachment, 57P01 normalization, listener removal, and release.
  • A real PostgreSQL child-process regression terminates the active backend while idle in a transaction, then proves the process survives and the transaction rejects with category: "connection" and code 57P01.
  • Guardrail (prevent this class of bug): Keep real backend-termination coverage in every supported PostgreSQL-version CI job; mocked query rejection alone is not sufficient for pooled-connection correctness.
  • Full ORM release gate, real PostgreSQL 16/17/18 hosted matrix, and exact-head CI pass before merge.

Definition of done

  • All acceptance criteria above are checked with evidence and the release-prepared exact-head PR is ready for squash merge as @askrjs/orm@0.0.2.

Severity

High — ordinary database failover, network loss, timeout termination, or administrative cancellation can otherwise terminate the host process.


Found via a real-PostgreSQL infrastructure-failure pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions