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>>(())
}
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 calltokio::task::yield_now().await
Reproducable