Search code examples
rustrust-tokio

`tokio::try_join!` on a vector of `JoinHandle`s


New to Rust. I want to wait for the following async tasks to finish:

let _ = tokio::try_join!(fetch_handle, evaluate_handles[0], evaluate_handles[1], evaluate_handles[2], evaluate_handles[3]);

Is there a way to do this without hard-coding each item in evaluate_handles? evaluate_handles is a Vec<JoinHandle<()>>, and fetch_handle is just a single JoinHandle<()>


Solution

  • In general, you can use TryJoinAll to do try_join! on an iterator of tasks (futures):

    use futures::future::TryJoinAll;
    let join_evaluate_handles = evaluate_handles.into_iter().collect::<TryJoinAll<_>>();
    

    In your case, all the join handles have the same type, so you could just construct an iterator that contains them all:

    evaluate_handles.into_iter()
        .chain(once(fetch_handle))
        .collect::<TryJoinAll<_>>()
        .await
    

    If they weren't the same type, you would combine TryJoinAll and try_join!:

    try_join!(fetch_handle, join_evaluate_handles /* from above */)
    

    Note, however, that I'm not sure it's super meaningful to use try_join here anyway. try_join's main point is that it returns immediately if one of the futures errors. But your futures are JoinHandles, and those only error when the spawned task panics: Playground Now, panicking in a spawned future makes tokio print an ugly error message, and you want to avoid that in general. The only practical use-case for using try_join here I can think of is aborting your application if a panic happens somewhere. But I think there's less hassle-full ways of doing this.


    One more note: If you're using TryJoinAll or FuturesUnordered, there's no real need to tokio::spawn your tasks in the first place.