Browse Source

make test_depends_deadlock more co-operative

This ensures that the threads which are blocking up the threadpool eventually exit when in failure mode.
pull/15388/head
oliver 1 month ago
parent
commit
21eee9163f
  1. 27
      tests/test_depends_deadlock.py

27
tests/test_depends_deadlock.py

@ -1,5 +1,4 @@
import asyncio
import multiprocessing
import threading
import time
from collections.abc import Iterator
@ -36,36 +35,14 @@ class Item(BaseModel):
# of the model and the cleanup of the Depends
@app.get("/deadlock", response_model=Item)
def get_deadlock(dep: None = Depends(release_resource)) -> Item:
mutex.acquire()
mutex.acquire(timeout=10)
return Item(name="foo", id=1)
# NOTE: the failure mode here can cause the test suite to hang.
# Since the default threadpool is a global which is not easily patched
# (and doing so would make the test somewhat fragile/pointless)
# we need to use a subprocess to isolate the bad behaviour.
# If you are struggling to debug, comment out this function and rename
# the impl_ version to test_depends_deadlock
def test_depends_deadlock() -> None:
proc = multiprocessing.Process(target=impl_test_depends_deadlock, daemon=True)
proc.start()
proc.join(timeout=10)
try:
assert not proc.is_alive(), (
"Process is still alive after timeout, likely due to a deadlock"
)
finally:
proc.kill() # Ensure the process is terminated if it's still alive
assert proc.exitcode == 0, "Process did not exit cleanly, see logs for details"
# Fire off 100 requests in parallel(ish) in order to create contention
# over the shared resource (simulating a fastapi server that interacts with
# a database connection pool).
def impl_test_depends_deadlock() -> None:
def test_depends_deadlock() -> None:
async def make_request(client: AsyncClient):
await client.get("/deadlock")

Loading…
Cancel
Save