1 个不稳定版本
0.6.0 | 2022年3月20日 |
---|
#666 在 异步
47KB
728 行
tokio-graceful-shutdown
此crate提供了在基于tokio-rs的服务上执行优雅关闭的实用函数。
具体来说,它提供
- 监听来自子系统的关闭请求
- 从子系统手动启动关闭
- 自动关闭
- SIGINT/SIGTERM/Ctrl+C
- 子系统故障
- 子系统panic
- 具有超时和错误传播的干净关闭程序
- 子系统嵌套
- 选择子系统树的局部关闭
使用示例
async fn subsys1(subsys: SubsystemHandle) -> Result<()>
{
log::info!("Subsystem1 started.");
subsys.on_shutdown_requested().await;
log::info!("Subsystem1 stopped.");
Ok(())
}
这显示了一个非常基本的异步子系统,它简单地启动,等待程序关闭被触发,然后停止自己。
现在可以像这样执行此子系统
#[tokio::main]
async fn main() -> Result<()> {
Toplevel::new()
.start("Subsys1", subsys1)
.catch_signals()
.handle_shutdown_requests(Duration::from_millis(1000))
.await
}
Toplevel
对象是子系统树的根对象。然后可以使用顶层对象的 start()
功能启动子系统。
catch_signals()
方法使 Toplevel
对象监听 SIGINT/SIGTERM/Ctrl+C 并随后启动关闭。
handle_shutdown_requests()
是 Toplevel
的最终且最重要的方法。它空闲直到程序进入关闭模式。然后,它收集所有子系统的返回值并确定全局错误状态,并确保在给定的超时内完成关闭。最后,它返回一个错误值,可以直接用作 main()
的返回代码。
更多示例可以在 examples 文件夹中查看。
构建
要在项目中使用此库,请将以下内容添加到 Cargo.toml
的 [dependencies]
部分
[dependencies]
tokio-graceful-shutdown = "0.5"
要运行示例之一(例如 01_normal_shutdown.rs
),只需进入仓库文件夹并执行
cargo run --example 01_normal_shutdown
动机
在异步程序中执行优雅的关闭是一个非平凡的问题。有几种解决方案,但它们都有各自的缺点
-
通过使用
tokio::select
进行全局取消。这是一个广泛使用的解决方案,但其缺点是取消的任务无法对此做出反应,因此它们无法优雅地关闭。 -
使用
tokio::spawn
进行分叉,并使用类似tokio::CancellationToken
的机制发出关闭正在运行的任务的愿望。这允许任务优雅地关闭,但需要大量的模板代码,如- 将令牌传递给任务
- 等待任务完成
- 实现超时机制以防止挂起
- 收集子系统返回值
- 确保正确处理子系统错误
如果还需要进一步的功能,例如监听像 SIGINT 或 SIGTERM 这样的信号,模板代码就会变得相当杂乱。
这正是这个crate的目标:为所有这些模板代码提供干净的抽象。
贡献
欢迎贡献!
我主要编写这个crate是为了自己的方便,所以任何改进的想法都备受赞赏。
依赖关系
~4–15MB
~149K SLoC