Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: async callbacks #388

Open
harochau opened this issue May 22, 2023 · 4 comments
Open

feature request: async callbacks #388

harochau opened this issue May 22, 2023 · 4 comments

Comments

@harochau
Copy link

harochau commented May 22, 2023

Looks like this library is supporting callbacks on transitions, but only regular ones.
I would like to use async def functions as callbacks, so I can use the same codebase (think async http requests, async database connections) in both API route handlers and state transitions.

@fgmacedo
Copy link
Owner

Hi @harochau , thanks for your suggestion. It would be nice to have async support.

Can you work on this? I'm still trying to figure it out how to have both sync and async on the same codebase.

@LoicRiegel
Copy link
Contributor

I am also interested in using this library with an async codebase

@berland
Copy link

berland commented Nov 10, 2023

I see no blockers with using this with async code. I just wrote this proof of concept:

import asyncio
from statemachine import State, StateMachine


class TrafficLightMachine(StateMachine):
    "A traffic light machine"
    green = State(initial=True)
    yellow = State()
    red = State()

    # Transitions
    slowdown = green.to(yellow)
    shortcut = green.to(red)
    stop = yellow.to(red)
    go = red.to(green)

    cycle = slowdown | go | stop | go | shortcut

    def before_slowdown(self):
        print("Slowdown")

    def before_cycle(self, event: str, source: State, target: State, message: str = ""):
        message = ". " + message if message else ""
        print(f"Running {event} from {source.id} to {target.id}{message}")
        return

    def on_enter_red(self):
        asyncio.create_task(dont_move(3))

    def on_exit_red(self):
        asyncio.create_task(go_ahead())

async def amain():
    sma = TrafficLightMachine()
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")
    await asyncio.sleep(0)
    sma.send("cycle")

async def dont_move(value):
    print(f"Don't move {value}")

async def go_ahead():
    print("Go ahead")

if __name__ == "__main__":
    asyncio.run(amain())

@fgmacedo
Copy link
Owner

@harochau @LoicRiegel @berland @xjules @sieroshtan can you help with tests/experimentation on the work done at PR #435?

Branch: macedo/async-sm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants