Skip to content

How to safely handle exceptions in async context? #509

@ale18V

Description

@ale18V
  • Python State Machine version: 2.5.0
  • Python version: 3.12
  • Operating System: Linux

Description

I ran into this issue: there may be multiple coroutines issuing events to the machine, yet if a coroutine triggers an invalid transition, a different coroutine may receive the exception instead.

Here is a simple example:

from statemachine import Event, State, StateMachine
import asyncio


class Test(StateMachine):
    INITIAL = State(initial=True)
    FINAL = State(final=True)

    noop = Event(INITIAL.to(FINAL))

    @noop.on
    async def do_nothing(self, name):
        await asyncio.sleep(10)
        print(f"Did nothing via {name}")


test = Test()


if __name__ == "__main__":

    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()

    async def fn1():
        await test.noop("fn1")

# Try/Except block is not working here
    async def fn2():
        try:
            await test.noop("fn2")
        except Exception as e:
            print(e)

    loop.create_task(fn1())
    loop.create_task(fn2())
    loop.run_forever()

Output is:

   ➜ python3 test.py 
Did nothing via fn1
Task exception was never retrieved
future: <Task finished name='Task-1' coro=<fn1() done> 
exception=TransitionNotAllowed("Can't Noop when in Final.")>
Traceback (most recent call last):
  File "test.py", line 29, in fn1
    await test.noop("fn1")
  File "/python3.12/site-packages/statemachine/engines/async_.py", line 66, in processing_loop
    result = await self._trigger(trigger_data)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/python3.12/site-packages/statemachine/engines/async_.py", line 96, in _trigger
    raise TransitionNotAllowed(trigger_data.event, state)
statemachine.exceptions.TransitionNotAllowed: Can't Noop when in Final.

It is clear that the invalid transition is triggered in fn2 yet the exception is thrown in fn1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions