Why does tokio::runtime::Handle::spawn appear to not run here?

It will work if I start main in a tokio runtime context with #[tokio::main] but I would like to adapt this code to be able to work in and outside of a runtime. If inside a runtime, it should use that existing runtime, if outside, it should create a runtime for itself to use.

fn runtime() -> (tokio::runtime::Handle, Option<tokio::runtime::Runtime>) {
    if let Ok(handle) = tokio::runtime::Handle::try_current() {
        (handle.clone(), None)
    } else {
        let runtime = tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .unwrap();
        (runtime.handle().clone(), Some(runtime))
    }
}

async fn another_async() -> anyhow::Result<()>{
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    println!("hello again!");
    Ok(()) 
} 

async fn hello_async() -> anyhow::Result<()>{
    println!("hello!");
    for _ in 0..10 {
        another_async().await?;
    }
    Ok(())
}


fn run_spawn() -> (tokio::runtime::Handle, Option<tokio::task::JoinHandle<anyhow::Result<()>>>) {
    let (runtime_handle, _runtime) = runtime();
    let join_handle = runtime_handle.spawn(hello_async());
    (runtime_handle.clone(), Some(join_handle))
}

fn main(){
   run_spawn();
   loop {}
}

(Playground)

A Handle does not keep the runtime alive - only the singly-owned Runtime type does. So you probably want to return an Option<Runtime> from that function.

1 Like

Thank you that fixed it. _runtime was being dropped at the end of run_spawn and aborting, I needed to return it to the main function or use std::mem::forget to prevent it from being dropped.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.