#[tokio::main]
async fn main() -> io::Result<()> {
// ...
let handle1 = tokio::spawn( async move {method1().await });
let handle2 = tokio::spawn( async move {method2().await });
let handle3 = tokio::spawn( async move {method3().await });
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(handle1, handle2, handle3)?;
match handle1_ret {
Ok(_) => info!("handle1 closed");
Err(e) => error!("handle1 failed");
}
match handle2_ret {
Ok(_) => info!("handle2 closed");
Err(e) => error!("handle2 failed");
}
match handle3_ret {
Ok(_) => info!("handle3 closed");
Err(e) => error!("handle3 failed");
}
Ok(())
}
tokio::try_join!
got stuck there even there is an error from method1
/method2
/method3
.
What I want is if method1
or method2
or method3
got any error, tokio::try_join!
should return and then the program should close (other running methods will terminate).
This is what try_join!
is designed to do. The reason you aren't really seeing it is because your handle{1,2,3}
tasks are actually returning Result
s of Result
s. Your method{1,2,3}
calls may return an error but the tokio::spawn
itself may also return an error (due to failure to spawn or task panic). So you really are .await
-ing a Result<Result<_, _>, _>
and try_join!
will only handle the outer Result
.
To get try_join!
to handle your method{1,2,3}
errors, you'll need to "flatten" your Result
s. A fairly straightforward way to do that is to ignore any tokio::spawn
errors since those are often unrecoverable:
let handle1 = tokio::spawn(async move { method1().await });
let handle2 = tokio::spawn(async move { method2().await });
let handle3 = tokio::spawn(async move { method3().await });
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(
async { handle1.await.unwrap() },
async { handle2.await.unwrap() },
async { handle3.await.unwrap() },
)?;
Or if you have a vacuous error type (Box<dyn Error>
, anyhow
, etc.) or otherwise has a From
impl for JoinError
you can just use ?
of course:
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(
async { handle1.await? },
async { handle2.await? },
async { handle3.await? },
)?;
Or really any other pattern matching on the Result
via match
, if let
, or whatever will let you handle it however you need. It just needs to be in that async { }
block you pass to try_join!
.