能否在Tokio优雅关闭实现中避免使用tokio::select!宏?
替代tokio::select!实现Axum优雅关闭的方案
当然有替代方案可以避免使用tokio::select!宏,以下是两种可行的实现方式:
方案一:使用futures::future::select组合子
借助futures crate中的select函数,可手动组合两个future并等待第一个完成的信号。需要先在Cargo.toml中添加futures依赖。
代码示例:
use tokio::signal; use futures::future::{select, Either}; pub async fn shutdown_signal() { let ctrl_c = async { signal::ctrl_c() .await .expect("failed to install Ctrl+C handler"); }; #[cfg(unix)] let terminate = async { signal::unix::signal(signal::unix::SignalKind::terminate()) .expect("failed to install signal handler") .recv() .await; }; #[cfg(not(unix))] let terminate = std::future::pending::<()>(); // 用futures::select替代tokio::select! match select(ctrl_c, terminate).await { Either::Left(_) => {}, // Ctrl+C信号触发 Either::Right(_) => {}, // 终止信号触发 } tracing::info!("signal received, starting graceful shutdown..."); }
方案二:将信号转为Stream后合并监听
利用tokio_stream crate将信号处理转为Stream,合并两个流后监听第一个到达的信号。需要添加tokio-stream依赖。
代码示例:
use tokio::signal; use tokio_stream::{StreamExt, wrappers::SignalStream}; pub async fn shutdown_signal() { // 处理Ctrl+C信号流 let ctrl_c_stream = SignalStream::new( signal::ctrl_c() .expect("failed to install Ctrl+C handler") ); #[cfg(unix)] let terminate_stream = { let sig_term = signal::unix::signal(signal::unix::SignalKind::terminate()) .expect("failed to install signal handler"); SignalStream::new(sig_term) }; #[cfg(not(unix))] let terminate_stream = tokio_stream::empty(); // 合并两个流,等待第一个信号 ctrl_c_stream.merge(terminate_stream).next().await; tracing::info!("signal received, starting graceful shutdown..."); }
注意事项
- 两种方案都需要额外引入第三方crate(
futures或tokio-stream),而原代码仅依赖tokio,需要权衡依赖复杂度。 tokio::select!本质是tokio提供的语法糖,在可读性和简洁性上更优,如果没有特殊限制,原方案其实是更合适的选择。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

