背景
spawn 后丢掉 handle,会让调用方失去等待、错误检查和取消入口。后台任务应该有生命周期所有者,而不是依靠进程退出兜底。
核心判断
- 单任务保存 JoinHandle,多任务使用 JoinSet 集中回收。
- 区分业务 Result 与 JoinError 中的 panic、取消。
- 优先协作停止,必要时 abort 后继续 await 回收结果。
最小示例
下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。
let handle = tokio::spawn(async move {
worker.run(shutdown).await
});
match handle.await {
Ok(Ok(())) => tracing::info!("worker stopped"),
Ok(Err(err)) => tracing::error!(error = %err, "worker failed"),
Err(err) => tracing::error!(error = %err, "worker join failed"),
}
边界与误区
丢弃 JoinHandle 会分离任务,并不等于停止任务。worker 和 shutdown 是业务对象,示例只展示持有 handle 和等待的边界。
验证方式
让任务正常返回、失败、panic 和被取消各一次,确认监督者都有处理路径;服务停止时检查没有孤立后台任务继续访问资源。
小结
保存 JoinHandle,集中处理任务完成、错误、panic 和取消,不让后台任务失去所有者。