-
-
Notifications
You must be signed in to change notification settings - Fork 111
Pure-async timeout() handler to avoid thread pool usage #613
Description
Context
The current timeout() helper in statemachine.contrib.timeout is implemented as a synchronous IInvoke handler that uses ctx.cancelled.wait(timeout=duration) (a threading.Event.wait()).
When used with the async engine, including alongside coroutine-function invoke targets (now supported after #611), the timeout handler runs in the default asyncio thread pool via loop.run_in_executor(None, handler.run, ctx) (statemachine/invoke.py:479). This works correctly, but each active timeout consumes a thread pool slot for the entire duration.
Proposal
Add an async-native timeout path using asyncio.sleep() and CancelledError, so that on the async engine:
- No thread pool slot is held while the timeout is pending.
- Cancellation is native (task cancellation at the next
await) rather than the current cooperativethreading.Eventsignalling.
The sync engine keeps the current thread-based implementation.
One implementation option: make _Timeout expose an async def run() in addition to the sync one, and let the engine's existing _has_async_run detection pick the async path on the async engine. The sync engine would keep using the sync run().
Related
- Does Invoke always run in a thread? #610 , invoke coroutine-function support
docs/timeout.md, current timeout documentation (would benefit from a short section on coroutine composition)