feat: per-user/per-database override for client_idle_timeout - #1467
Open
mvidaurre wants to merge 8 commits into
Open
feat: per-user/per-database override for client_idle_timeout#1467mvidaurre wants to merge 8 commits into
mvidaurre wants to merge 8 commits into
Conversation
client_idle_timeout was previously global-only, disconnecting long-idle LISTEN/NOTIFY subscribers with no way to exempt them. Add an Option<u64> override on User and Database (users.toml / pgdog.toml), resolved with the same user -> database -> general precedence used elsewhere (idle_timeout, statement_timeout). 0 at any level exempts the client from the timeout entirely. Fixes pgdogdev#1462 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NoNS7QBkAU2apgWGLFuMMp
mvidaurre
marked this pull request as ready for review
September 1, 2026 02:28
The per-user/per-database override work moved timeout resolution to ConfigAndUsers::client_idle_timeout(user, database), where 0 means "disabled". This method was no longer called anywhere but still treated 0 as "time out immediately", the opposite of the new rule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The per-user/per-database override work made 0 mean "disabled" at every level, including general.client_idle_timeout (previously 0 meant "time out immediately" via the now-removed General::client_idle_timeout() method). Document this explicitly, matching the notes already added to the database/user overrides. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- User-level resolution now takes the last matching entry that actually configures the setting, so bare entries appended by passthrough auth (or broader later entries without the setting) no longer erase an earlier override. Regression test included. - The virtual admin database is exempt from user/database overrides, matching pool construction which never associates users with it. Regression test included. - Extracted Config::database_client_idle_timeout() so first-wins resolution for duplicate [[databases]] entries lives in one place, and rewrote the Config::check merge as a match without shadowed bindings. - Replaced Weak::upgrade + Arc::ptr_eq on the per-request hot path with a plain pointer compare (our own Weak pins the allocation, so no ABA). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace filter_map().last() with rev().find_map() — short-circuits from the end instead of walking every user entry, and avoids clippy's double_ended_iterator_last. Drop the redundant config_admin_user() test helper in favor of Admin::default(). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
client_idle_timeoutis currently global. That works for ordinary request/response clients, but it also disconnects intentionally quiet sessions such asLISTEN/NOTIFYsubscribers. PostgreSQL settings cannot prevent this because PgDog applies the timeout to the frontend socket before PostgreSQL is involved.This change makes the timeout configurable per user or logical database, so operators can exempt only long-lived listeners without weakening idle-client protection for everyone else.
Fixes #1462.
Configuration and precedence
Resolution follows the same precedence used by other PgDog overrides:
[general].client_idle_timeoutAt every level,
0means disabled for that client (Duration::MAX).Exempt one user
Override one logical database
A logical database may have multiple
[[databases]]entries for shards or replicas. The first configured non-Noneoverride is used across the logical database. Conflicting configured values produce a warning rather than depending silently on physical-entry ordering.When user entries overlap through
all_databasesordatabases, the last matching entry that configuresclient_idle_timeoutwins. A later matching entry without this setting does not erase an earlier override; this preserves explicit policy when passthrough authentication appends a bare user entry.Authenticated admin sessions always use the general timeout because the admin database is virtual and has no user or backend database configuration.
Implementation
client_idle_timeout: Option<u64>toUserandDatabase, including database-URL query parameter support.ConfigAndUsers::client_idle_timeout(user, database)to centralize precedence and0handling.useranddatabasein regular and mirror client paths, while retaining the authenticated admin flag across reloads.Weak<ConfigAndUsers>:buffer()invocation; an already pending idle read retains its current deadline until the client loop wakes;docs/CLIENT_CONNECTION.mdand the example configuration files.Reviewer guide
pgdog-config/src/users.rs,pgdog-config/src/database.rs,pgdog-config/src/url.rs,.schema/*pgdog-config/src/core.rspgdog/src/frontend/client/timeouts.rs,pgdog/src/frontend/client/mod.rspgdog/src/backend/pool/connection/mirror/mod.rspgdog/src/frontend/client/test/mod.rs, timeout/config unit testsCompatibility
client_idle_in_transaction_timeoutand backendidle_timeoutbehavior are unchanged.LISTENregistrations automatically.client_idle_timeout = 0now consistently means disabled at general, database, and user levels.Validation
cargo fmt --all -- --checkcargo nextest run --profile dev -p pgdog-config --lib— 124 passedcargo nextest— 7 passedcargo clippy -p pgdog-config -p pgdog --all-targets— no warnings introduced by this PRcargo run -p pgdog-jsonschema)main;cargo check -p pgdog-config -p pgdogpassed