Repository navigation
Conversation
Keep NOTICE responses informational and restore built-in client RESET suppression. Avoid replaying Greengage startup metadata and remove duplicate cleanup warnings. Add a disposable pinned Greengage cluster to the Docker Nix runner and CI, cover cleanup and RELOAD behavior with BDD, and update Russian and English documentation.
Track the actual frontend bundle through the existing directory and recursive file watches. Remove the nonexistent index.html dependency that made every Cargo invocation rebuild pg_doorman.
A query replaces the built-in cleanup commands, so it belongs to `always` alone. Validate the effective mode and query of every pool instead of the general block only: a pool that inherits a query and narrows the mode to `adaptive` silently changes what the cleanup does. `off` keeps accepting an inherited query, because a pool may raise another pool to `always`. Document the pairing, the commands `adaptive` does not track, and refresh the generated reference configs.
DISCARD ALL resets every GUC on the backend, including startup parameters that never reported ParameterStatus, so the remembered startup values went stale for the next checkout. Drop them from the snapshot instead of re-arming cleanup: a configured query now exists only in the `always` mode, which runs it regardless of the tracked state, so the re-arm could not change the outcome. Cover mode inheritance and the built-in cleanup commands counted in the PostgreSQL log.
Documentation said the same pairing rule three times in different words and listed the adaptive limitations as a pile of exceptions. State the rule once, separate what adaptive tracks from what it does not, and give a Greengage query that actually clears temporary tables on segments: DISCARD TEMP does that, the previous example omitted it and then apologised for the gap. Comments in the server, stats and metrics code explained the line below them or repeated the metric help text. Keep only the notes that carry a fact the code does not show: startup parameters a backend never reports back, why a maintenance failure must not replace a completed result, why a partially reset backend is never returned to the pool.
…etry The TLS retry replaces the plain attempt, and a protocol-level plain failure logs nothing on its own, so a backend that never started leaves only the retry error behind: "tls required but server does not support tls" against a Postgres with ssl=off, which says nothing about why the plain connection was rejected. Report the original error in both retry lines: local backend and fallback candidate.
…sentences pg_doorman re-prepares its own cached prepared statements after a cleanup query, so only client-side named PREPARE/EXECUTE break.
…er default DISCARD ALL is PgBouncer's default server_reset_query, and PostgreSQL lists the exact statement sequence it expands to.
…ncer 3.11.2 is released, so the feature belongs to a new section. The cleanup query example is PgBouncer's default server_reset_query, which is the reference our users compare against.
The protocol guards warned, mark_bad logged the same reason, and the checkin_cleanup wrapper logged the outcome: three lines for one incident. Keep mark_bad and the wrapper line.
The counter was only mentioned in the changelog. Spell out what it counts in each cleanup mode, that result="error" means a retired backend, and that the database label is the pool name.
cleanup_legacy described neither the mode nor the work. The rollback runs in every mode, the RESET sequence only in adaptive, so the call site now computes needs_rollback and needs_session_reset and passes the latter in.
off rolls back a transaction the client left open and sends nothing else. adaptive adds the built-in reset for a changed session, including the DEALLOCATE ALL that re-synchronizes a Parse the client never flushed.
vadv
force-pushed
the
feat/configurable-backend-cleanup
branch
3 times, most recently
from
October 7, 2026 06:58
964a7b7 to
f9b6e1a
Compare
Add cleanup_server_connections modes off, adaptive, always and the cleanup_server_query setting. Both work in [general] and per pool. - adaptive (default). Built-in cleanup SQL runs only after a tracked session state change. - always. cleanup_server_query runs on every checkin of a backend that served a client. The query is required. - off. No session cleanup. ROLLBACK for an open transaction still runs. Legacy true and false mean adaptive and off. Adaptive detection covers SET, DECLARE cursors and the prepared statement cache. This commit adds SQL PREPARE, LISTEN and CREATE TEMP TABLE: - SQL PREPARE -> DEALLOCATE ALL. SQL PREPARE shares the server-side statement namespace with an extended-protocol Parse. Without tracking, the next client on the backend failed with 42P05. - LISTEN -> UNLISTEN *. A pooled backend's socket is not read, so queued notifications reached the client that checked the backend out next. - CREATE TEMP TABLE -> DISCARD TEMP. The CREATE TABLE tag does not distinguish temp from permanent tables; DISCARD TEMP is a no-op for permanent objects. SELECT INTO TEMP and CREATE TEMP TABLE AS SELECT complete with the inner query's tag on current PostgreSQL and stay untracked. - Every cleanup batch releases advisory locks with pg_advisory_unlock_all(). A failed cleanup retires the backend. Responses already sent to the client stay delivered. Client RESET and DISCARD ALL still suppress built-in cleanup in adaptive. Tests: BDD scenarios cover the leaks before the fix, the suppression rules, async boundaries, observability metrics and a real Greengage cluster. Docs: pool reference, concept pages, config examples and the changelog.
vadv
force-pushed
the
feat/configurable-backend-cleanup
branch
from
October 7, 2026 07:00
f9b6e1a to
8d4b541
Compare
This branch has not been deployed
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.
Add two settings:
cleanup_server_connectionsmodesoff,adaptive,always, andcleanup_server_query. Both work in[general]and per pool.adaptive(default). Built-in cleanup SQL runs only after a tracked session state change.always.cleanup_server_queryruns on every checkin of a backend that served a client. The query is required.off. No session cleanup.ROLLBACKfor an open transaction still runs.Legacy
trueandfalsemeanadaptiveandoff.cleanup_server_queryreplaces the built-inRESET ROLE/RESET ALL/DEALLOCATE ALL/CLOSE ALLsequence. A good example is PgBouncer's defaultserver_reset_query:DISCARD ALL. Validation checks the pair as a whole:alwaysrequires a query.adaptiverejects a query. A pool without its own settings inherits both from[general].Adaptive detection
The built-in cleanup tracks these statements and answers with cleanup SQL:
SETRESET ALLDECLAREcursorCLOSE ALLPREPAREDEALLOCATE ALLLISTENUNLISTEN *CREATE TEMP TABLEDISCARD TEMPEvery cleanup batch also releases advisory locks with
pg_advisory_unlock_all().Motivation:
PREPAREand an extended-protocolParseshare one statement namespace. Without tracking, the next client on the same backend failed with42P05 duplicate_prepared_statement.NotificationResponsemessages reached the client that checked the backend out next.Not tracked:
SELECT ... INTO TEMPandCREATE TEMP TABLE AS SELECT. Current PostgreSQL completes them with the inner query's tag. Temporary objects inside functions carry no tag. Usealwayswith suitable SQL for these.Behavior
COMMIT.NOTICEfrom the cleanup query goes to the client. It is not an error and does not retire the backend.RESETorDISCARD ALLsuppresses built-in cleanup inadaptive. It never suppressesalways.Tests
LISTENsubscriptions, cross-client notifications, SQLPREPAREcollisions, advisory locks.make test-greengageruns@greengagescenarios on a pinned Greengage 7.5 image with one coordinator and two primary segments. These tests also run in CI.Scope
pg_doorman_server_cleanup_totalmetric.Other changes
pg_doorman_server_cleanup_totalwith labelsuser,database,result(ok/error).pg_doorman.toml,pg_doorman.yaml, and the English and Russian documentation.Upgrade notes
trueandfalsekeep working.SHOWand config dumps omit pool-levelcleanup_server_connectionswhen the pool does not set its own. Treat the field as optional in parsers.cleanup_server_connections = "always"and a cleanup query withDISCARD TEMP. GreengageDISCARD ALLleaves temporary tables on segments. See the pool reference for an example.adaptivemode. If a client holds session-level advisory locks across transactions, use session pooling oroff.CREATEat the next checkin. Keep a transaction open across the statements that use the table, or use session pooling.