awestlake87 / pyo3-asyncio

Other
300 stars 45 forks source link

no running event loop #101

Closed vitalik closed 1 year ago

vitalik commented 1 year ago

Hi

I'm a bit stuck trying to make actix webserver to call async python function

here I created demo repo

https://github.com/vitalik/pyactix

just install maturin and run sh test.sh

the sync function works

but async does not: https://github.com/vitalik/pyactix/blob/84606e563b191ce0eb22e5cd59cf9cb0ee9bd004/test.py#L7-L9

when calling http://localhost:8000/foo

I'm getting : no running event loop

Any advice ?

🌍 Environment

awestlake87 commented 1 year ago

The reason you're getting this error is because Python uses thread-local variables to determine which event loop it should use when asyncio.get_running_loop is called.

You created an event loop here: https://github.com/vitalik/pyactix/blob/84606e563b191ce0eb22e5cd59cf9cb0ee9bd004/src/server.rs#L69

but asyncio.set_running_loop only works for the current thread. Your handler runs on a separate thread, so you need to somehow tell pyo3-asyncio that it needs to use this event loop.

You should be able to accomplish this with pyo3_asyncio::into_future_with_locals. You can construct TaskLocals with a reference to your event loop.

vitalik commented 1 year ago

@awestlake87 Thank you!

I assume scope_local does the same thing (by passing locals that was created before) ? or I should use into_future_with_locals. + &pyo3_asyncio::tokio::get_current_locals(py)?

here is current version that seems working:

https://github.com/vitalik/pyactix/blob/0dfb329c65fc71019071d0b7f9efcc38531a7602/src/server.rs#L87

awestlake87 commented 1 year ago

Yeah, scope_local allows you to store the event loop as a task local so you can use the less explicit conversions throughout that task. into_future_with_locals is more explicit since you have to manually pass it the task locals, but it works the same. Whichever is most convenient.