DelSkayn / rquickjs

High level bindings to the quickjs javascript engine
MIT License
434 stars 59 forks source link

Nested spawned tasks not executed unless explicit call to tokio::task::yield_now() #236

Closed richarddd closed 8 months ago

richarddd commented 8 months ago

If the outer task hasn't completed yet and nested tasks are spawned via ctx.spawn() the inner task doesn't start unless I explicitly call tokio::task::yield_now().await

Reproducable

use rquickjs::{
    loader::{BuiltinResolver, FileResolver, ModuleLoader, ScriptLoader},
    prelude::Func,
    AsyncContext, AsyncRuntime, Ctx, Object,
};
use tokio::net::TcpListener;

fn print(msg: String) {
    println!("{}", msg);
}

#[tokio::main]
async fn main() -> core::result::Result<(), Box<dyn std::error::Error>> {
    let resolver = (
        BuiltinResolver::default(),
        FileResolver::default().with_path("."),
    );
    let loader = (ModuleLoader::default(), ScriptLoader::default());

    let rt = AsyncRuntime::new().unwrap();
    rt.set_max_stack_size(512 * 1024).await;
    rt.set_loader(resolver, loader).await;

    let ctx: AsyncContext = AsyncContext::full(&rt).await.unwrap();

    let _res = ctx
        .with(|ctx| -> rquickjs::Result<()> {
            let globals = ctx.globals();

            let console = Object::new(ctx.clone())?;
            console.set("log", Func::from(print))?;
            globals.set("console", console)?;

            globals.set(
                "serve",
                Func::from(|ctx| {
                    struct Args<'js>(Ctx<'js>);
                    let Args(ctx) = Args(ctx);
                    let port = 3000;
                    ctx.clone().spawn(async move {
                        let listener = TcpListener::bind(format!("0.0.0.0:{}", port))
                            .await
                            .unwrap();

                        println!("Listening on port {}", port);

                        loop {
                            let (_stream, _) = listener.accept().await.unwrap();
                            ctx.spawn(async move { println!("Incoming data!") });
                            tokio::task::yield_now().await; //<--- IF THIS IS OMITED THE SPAWN ABOVE DOESN'T EXECUTE
                        }
                    })
                }),
            )?;

            ctx.eval::<(), _>("serve()")?;

            Ok(())
        })
        .await;

    rt.idle().await;

    drop(ctx);
    drop(rt);

    Ok::<_, Box<dyn std::error::Error>>(())
}
richarddd commented 8 months ago

There is something else going on, can't reproduce on latest commit... Closing for now