Skip to content

PYTHON-6074 Fix pool deadlock when a greenlet is killed during checkin - #23

Closed
blink1073 wants to merge 10 commits into
mainfrom
PYTHON-6074-gevent-deadlock
Closed

PYTHON-6074 Fix pool deadlock when a greenlet is killed during checkin#23
blink1073 wants to merge 10 commits into
mainfrom
PYTHON-6074-gevent-deadlock

Conversation

@blink1073

Copy link
Copy Markdown
Owner

PYTHON-6074

Changes in this PR

Under gevent, killing a greenlet that is checking a connection back into the pool can leave the pool's requests and active_sockets counters permanently inflated at maxPoolSize. Every later checkout then blocks forever on the size-gate wait, freezing all database operations for the process. This change makes the pool's checkin accounting uninterruptible by a GreenletExit, so the counters and the connection are always restored.

  • Made Pool.checkin apply its counter decrement and connection return in one critical section, re-applying them if a GreenletExit interrupts before they complete.
  • Added test_gevent_kill_churn_deadlock, which runs workers and a killing reaper under gevent and fails if operations stall.
  • Documented the fix in the 4.19.0 changelog.

Test Plan

  • Reproduced the deadlock on unmodified code with the reporter's reproducer (300 workers, maxPoolSize 3, a kill every 20 ms, no waitQueueTimeoutMS); the same script runs clean for 5 minutes with the fix.
  • The new regression test fails on unmodified code and passes with the fix. The existing gevent tests (test_gevent_task, test_gevent_timeout, test_gevent_timeout_when_creating_connection) still pass.
  • Non-gevent pool tests pass. just lint and just typing are clean.

# Conflicts:
#	doc/changelog.rst
Under gevent, notify() is a yield point, so a kill delivered inside
it left accounted False and the fallback decremented the accounting
a second time. Set the flag before notify() so only interruption
during condition acquisition triggers the fallback.
Adds a test interrupting the error handler while it waits to
acquire size_cond, covering the fallback that re-applies the
checkout accounting.
When AMPLIFY_RACE is enabled the test reassigns gevent.thread.sleep
globally; register a cleanup so the widened sleep window doesn't leak
into later tests.
Comment thread test/asynchronous/test_client.py Outdated
Comment thread test/asynchronous/test_client.py Outdated
@blink1073 blink1073 closed this Sep 8, 2026
@blink1073
blink1073 deleted the PYTHON-6074-gevent-deadlock branch September 8, 2026 17:28
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.

1 participant