Skip to content

Pure-async timeout() handler to avoid thread pool usage #613

@fgmacedo

Description

@fgmacedo

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 cooperative threading.Event signalling.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions