Skip to content

Feature Request: Add non-gather mode for AsyncMachine callbacks #717

@JIAQIA

Description

@JIAQIA

Feature Request: Add non-gather mode for AsyncMachine callbacks

Problem Description

Currently, AsyncMachine executes callbacks using asyncio.gather(), which creates a potential issue when managing resource lifecycles across different state transitions.

The problem manifests when:

  1. Opening resources in one transition callback (e.g., on_enter_connect)
  2. Closing those same resources in another transition callback (e.g., on_enter_disconnect)

Because asyncio.gather() runs callbacks in separate tasks, this creates a task boundary violation for context managers that require opening/closing in the same task (e.g., anyio cancel scopes, async_exit_stack, etc.).

Current Workaround

I've implemented a temporary solution by subclassing AsyncMachine:

class A2CAsyncMachine(AsyncMachine):
    @staticmethod
    async def await_all(callables: list[Callable]) -> list:
        ret = []
        for c in callables:
            ret.append(await c())
        return ret

This works but isn't ideal for long-term maintenance.

Proposed Solution

Add a configuration flag to control callback execution mode:

machine = AsyncMachine(..., gather_callbacks=False)  # Default True for backward compatibility

When False, callbacks would execute sequentially in the same task rather than via asyncio.gather().

Benefits

  1. Maintains backward compatibility
  2. Gives users control over execution model
  3. Solves task-boundary issues for context managers
  4. Still allows parallel execution when desired (default mode)

Potential Considerations

  1. Performance impact for users who don't need sequential execution
  2. Need to verify no other parts of the code assume gather behavior
  3. Documentation updates to explain the tradeoffs

Environment

  • OS: macOS Ventura
  • Python: 3.11
  • Library: transitions (latest main branch)

Would appreciate maintainers' thoughts on this approach. Happy to submit a PR if this direction is approved.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions