Skip to content

Bound close(timeout) around a pending cancel - #1361

Merged
elprans merged 3 commits into
MagicStack:masterfrom
gyanu2507:fix/close-timeout-pending-cancel
Sep 21, 2026
Merged

elprans merged 3 commits into
MagicStack:masterfrom
gyanu2507:fix/close-timeout-pending-cancel

Conversation

@gyanu2507

@gyanu2507 gyanu2507 commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1356.

close(timeout=) waits for cancel_waiter before it applies timeout. That future is only completed when ReadyForQuery arrives on the original socket. _on_connection_lost resolves waiter and leaves the cancel futures pending, so a frozen server (or a pooler that then drops the client) can leave close() hung forever.

SQLAlchemy's asyncpg dialect hits this when it invalidates a connection after TimeoutError with close(timeout=2).

The cancel wait now uses the same timeout, a lost transport completes the cancel futures, and abort() still drops the socket if close() already set closing.

gyanu2507 and others added 3 commits September 18, 2026 23:04
close() awaited cancel_waiter with no timeout, and connection_lost
only resolved waiter. A frozen server left close() hanging even
after the socket dropped.

Fixes MagicStack#1356

@elprans elprans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a bit more robustness to cancellation drainage and made it so that cancellation shares the close operation timeout budget.

@elprans
elprans merged commit c06bcb4 into MagicStack:master Sep 21, 2026
91 of 106 checks passed
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.

Connection.close(timeout=) waits forever on a pending cancel when the server never acknowledges it

2 participants