We tried Event, Condition, and Queue. Each one gets closer but still breaks under real concurrency. Here's the observable pattern that finally works.
Coordinating concurrent tasks around shared state is one of the most common problems in Python's asyncio . The standard library gives you asyncio.Event and asyncio.Condition , but each has a gap that only shows up under real concurrency pressure. We hit this while building Inngest's Python SDK, where multiple async handlers coordinate around WebSocket connection state.
This post works through each primitive, shows exactly where it breaks, and iterates toward a solution that handles every case we threw at it.
The scenario
Imagine an async Python app managing a connection that moves through states:
txt disconnected → connecting → connected → closing → closed
One of your concurrent handlers needs to drain pending requests when the connection starts shutting down. It has to wait for the closing state:
state = "disconnected" async def drain_requests ( ) : . . . print ( "draining pending requests" )
Simple enough. Let's see how each stdlib tool handles it.
Attempt 1: Polling
... continue reading