Spawning a tokio task in a library

im making a library and theres a method that when called should do something after a duration in the background, this is what i came up with

pub async fn exec_temp(client: &Client, duration: Duration) -> Result<Resp> {
  let resp = exec(client).await?;
  let resp_id: u64 = resp.id;
  tokio::spawn(async move {
    tokio::time::sleep(duration).await;
    let _ = destroy(client, resp_id).await;
  });
  Ok(resp)
}

but theres a few issues with this

  • the result returned later cant be handled
  • the background task cant be cancelled

but i have a bigger problem, if i have a reference to the client, i cant use that to spawn a task (apparently?) i could take an Arc<Client> but in the real world users will have an Arc<Context> which wraps over that client so yeah idk what to do now

so what do you think is a better approach for this? thank you :‍)

You will need to have the Arc<Client> - there's not really any other option. tokio::spawn() returns a task, which (like a thread) could potentially run forever, so there's no way you can pass a reference to a task.

Could you have an Arc<Context> that contains an Arc<Client>, and then pass a clone() of the Arc<Client> to the task?

thank you! the best choice seems like changing the parameter to client: Arc<Client> then, and in reality client is in a Bot { client: Client } so i should make that Bot { client: Arc<Client> }, is it a good design to nest Arcs by the way?

Yes, you can nest Arcs. I do it all the time - a very common struct in my apps is:

struct AppEnv {
    // Environment variables
}
struct AppState {
    env: Arc<AppEnv>
    // Other state stuff
}

let state: Arc<AppState> = ...

thank you! that's a breaking change so it'll have to wait sadly

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.