#优雅关闭 #关闭 #tokio #子系统 #执行 #错误 #服务

tokio-graceful-shutdown-without-anyhow

用于在基于Tokio的服务上执行优雅关闭的实用程序

1 个不稳定版本

0.6.0 2022年3月20日

#666异步

Apache-2.0

47KB
728

tokio-graceful-shutdown

Crates.io Crates.io License Build Status docs.rs Coverage Status

此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