为什么要关心停机 很多人写异步服务时,把注意力都放在“怎么启动”,很少认真想“怎么结束”。
但线上真正麻烦的,往往是停机阶段:
Kubernetes 滚动发布,Pod 收到 SIGTERM 服务还在处理请求,但新流量已经切走 后台任务没停干净,日志和指标都丢了 数据库连接突然断掉,导致半成功半失败 如果退出流程没有设计好,服务看起来可用,实际上很难运维。
Tokio 默认不会帮你解决一切 Tokio 的运行时很好用,但它不会自动替你处理这些问题:
谁来监听退出信号 如何通知所有任务停止 正在跑的任务是立即取消,还是等它收尾 超时之后要不要强制退出 这些都需要业务自己定义。
一个基础模型 一个比较稳妥的思路是分三步:
接收退出信号 广播 shutdown 事件 等待任务收尾,必要时超时强退 先看一个简化版结构:
use tokio::signal; use tokio::sync::broadcast; use tokio::time::{timeout, Duration}; #[tokio::main] async fn main() -> anyhow::Result<()> { let (shutdown_tx, _) = broadcast::channel::<()>(16); let server_handle = tokio::spawn(run_http_server(shutdown_tx.subscribe())); let worker_handle = tokio::spawn(run_background_worker(shutdown_tx.subscribe())); signal::ctrl_c().await?; println!("received shutdown signal"); let _ = shutdown_tx.send(()); let _ = timeout(Duration::from_secs(10), async { let _ = server_handle.await; let _ = worker_handle.await; }).await; Ok(()) } 这段代码表达的核心思想很重要:
...