Skip to content

fix: don't hand clients a connection Postgres already closed - #1318

Merged
levkk merged 3 commits into
pgdogdev:mainfrom
nsavvide:feat/detect-closed-server-connection
Aug 7, 2026
Merged

fix: don't hand clients a connection Postgres already closed#1318
levkk merged 3 commits into
pgdogdev:mainfrom
nsavvide:feat/detect-closed-server-connection

Conversation

@nsavvide

@nsavvide nsavvide commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Healthchecks only run every healthcheck_interval (30s by default), so a backend terminated by pg_terminate_backend or an admin restart stayed in the pool and was handed to clients unchecked until the interval elapsed.

Adds a non-blocking liveness peek on every checkout. An idle pooled connection should have nothing waiting to be read, so pending bytes or a closed socket disqualify it: the connection is force-closed and the existing retry loop fetches another.

Pending data is treated as fatal without parsing it. That also discards connections that merely received an asynchronous NoticeResponse, which costs a reconnect but never correctness, and keeps the check cheap enough to run on every checkout.

Uses a distinct Error::ServerClosed rather than HealthcheckError so a dead connection does not toggle pool health. The check runs far more often than a healthcheck, and one terminated backend must not ban the pool or trigger failover.

Closes #614

Healthchecks only run every healthcheck_interval (30s by default), so a
backend terminated by pg_terminate_backend or an admin restart stayed in
the pool and was handed to clients unchecked until the interval elapsed.

Adds a non-blocking liveness peek on every checkout. An idle pooled
connection should have nothing waiting to be read, so pending bytes or a
closed socket disqualify it: the connection is force-closed and the
existing retry loop fetches another.

Pending data is treated as fatal without parsing it. That also discards
connections that merely received an asynchronous NoticeResponse, which
costs a reconnect but never correctness, and keeps the check cheap enough
to run on every checkout.

Uses a distinct Error::ServerClosed rather than HealthcheckError so a
dead connection does not toggle pool health. The check runs far more
often than a healthcheck, and one terminated backend must not ban the
pool or trigger failover.

Closes pgdogdev#614
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.23077% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pgdog/src/net/stream.rs 98.33% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@levkk

levkk commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Fantastic! Let me benchmark this locally to double check that this doesn't have a performance impact!

@levkk

levkk commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Strangely I see absolutely no performance regression here..which is good of course, but I expected this to make an extra syscall on each checkout! I'm going to wait for GH actions to come back to life and probably merge this as-is. Great work!

Comment thread pgdog/src/backend/pool/pool_impl.rs Outdated
@nsavvide
nsavvide requested a review from levkk August 7, 2026 11:50
@nsavvide

nsavvide commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Strangely I see absolutely no performance regression here..which is good of course, but I expected this to make an extra syscall on each checkout! I'm going to wait for GH actions to come back to life and probably merge this as-is. Great work!

Makes sense, now_or_never() polls the peek once, and tokio checks cached readiness first, so on a healthy idle connection it returns Pending without ever issuing recv(MSG_PEEK). The syscall only happens when the fd is already flagged readable, i.e. when there's genuinely something pending.

@levkk
levkk merged commit 979e469 into pgdogdev:main Aug 7, 2026
49 checks passed
@nsavvide
nsavvide deleted the feat/detect-closed-server-connection branch August 7, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Healthchecks] Dont give connection to client that's been shut down

2 participants