awestlake87 / pyo3-asyncio

Other
302 stars 46 forks source link

Coroutine not being awaited: No event loop running. #57

Closed sansyrox closed 2 years ago

sansyrox commented 2 years ago

πŸ› Bug Reports

Hi,

I was trying to run a Python async function in the actix web sockets in Robyn.

I am trying to execute an async function but it is telling me that the event loop is not running. But I am pretty sure that the event loop is running as the other async functions are being executed in the HTTP routers.

Below is my implementation

 Ok(ws::Message::Text(text)) => {
                // need to also passs this text as a param
                let handler_function = &self.router.get("message").unwrap().0;
                let _number_of_params = &self.router.get("message").unwrap().1;
                println!("{:?}", handler_function);
                match handler_function {
                    PyFunction::SyncFunction(handler) => Python::with_gil(|py| {
                        let handler = handler.as_ref(py);
                        // call execute function
                        let op = handler.call0().unwrap();
                        let op: &str = op.extract().unwrap();

                        return ctx.text(op);
                    }),
                    PyFunction::CoRoutine(handler) => {
                        println!("{:?}", handler);
                        let fut = Python::with_gil(|py| {
                            let handler = handler.as_ref(py);
                            let coro = handler.call0().unwrap();
                            pyo3_asyncio::tokio::into_future(coro)
                        });

                        let f = async move {
                            fut.unwrap().await.unwrap();
                        };
                        let x = actix::fut::wrap_future::<_, Self>(f);
                        ctx.spawn(x);
                        // ctx.add_stream("Hello, world");
                        return ctx.text("Async Functions are not supported in WS right now.");
                    }
                }
            }

But I am getting the following error:

sys:1: RuntimeWarning: coroutine 'connect' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
thread 'actix-rt|system:0|arbiter:0' panicked at 'called `Result::unwrap()` on an `Err` value: PyErr { type: <class 'RuntimeError'>, value: RuntimeError('no running event loop'), traceback: None }', src/web_socket_connection.rs:101:33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

🌍 Environment

πŸ’₯ Reproducing

Please provide a minimal working example. This means both the Rust code and the Python.

Please also write what exact flags are required to reproduce your results.

Here is the PR that I created: https://github.com/sansyrox/robyn/pull/134

maturin develop is the command to run it.

ShadowJonathan commented 2 years ago

Looking at your codebase, with normal requests, you scope the coroutine locally with the event loop object (see src/server.rs:143~145), however, you're not doing that with the corresponding websocket object(s), so you have to pass around the event loop there to then scope the coroutine future with.

awestlake87 commented 2 years ago

Sorry for the delay! @ShadowJonathan is right, you'll probably have to pass the event loop reference through start_web_socket to MyWs, then pass it to pyo3_asyncio::into_future_with_loop when converting your message handler coroutine here

sansyrox commented 2 years ago

Thank you @ShadowJonathan @awestlake87 :D

Passing the event loop(https://github.com/sansyrox/robyn/pull/134/files#diff-0d0da7574dadb5452e2f359138c914a901f38425138f1c2facc37f403b98ab7fR136) worked for me. :D