Race condition when using AsyncTimeout · Issue #459 · pytransitions/transitions (original) (raw)

Consider the following example:

import asyncio

from transitions.extensions.asyncio import AsyncMachine, AsyncTimeout from transitions.extensions.states import add_state_features

@add_state_features(AsyncTimeout) class CustomMachine(AsyncMachine): pass

class Model: async def on_enter_completed(self): print('entered completed state')

async def on_enter_waiting(self):
    print('entered waiting state')

async def main(): model = Model()

states = [
    'start', 
    { 'name': 'waiting', 'timeout': 0.5, 'on_timeout': 'to_waiting' },
    'completed',
]
machine = CustomMachine(model, states, initial='start')
machine.add_transition('wait', 'start', 'waiting')
machine.add_transition('complete', 'waiting', 'completed')

await model.wait()
await asyncio.sleep(1.0)
await model.complete()

loop = asyncio.get_event_loop() loop.create_task(main()) loop.run_forever() loop.close()

The intended behavior is for it to loop on the waiting state a few times, then transition to the completed state and stop. However, the output looks like this:

entered waiting state
entered waiting state
entered completed state
entered waiting state
entered waiting state
entered waiting state
entered waiting state
[...repeats forever...]

It seems that the timer that transitions back to the waiting state does not get properly canceled when we transition to the completed state.