7个版本

0.1.6 2023年12月1日
0.1.5 2023年9月20日

#79异步

Download history 364/week @ 2024-04-08 338/week @ 2024-04-15 515/week @ 2024-04-22 455/week @ 2024-04-29 877/week @ 2024-05-06 1008/week @ 2024-05-13 660/week @ 2024-05-20 1014/week @ 2024-05-27 692/week @ 2024-06-03 821/week @ 2024-06-10 735/week @ 2024-06-17 795/week @ 2024-06-24 699/week @ 2024-07-01 1275/week @ 2024-07-08 877/week @ 2024-07-15 542/week @ 2024-07-22

3,451 每月下载量
8 个crate中使用 (5个直接使用)

MIT/Apache

46KB
601 代码行

Crates.io Docs.rs MIT License Apache 2.0 License Build Status

Buy Me A Coffee GitHub Sponsors

tokio应用程序优雅关闭的管理。创建和使用守卫是锁免费的,该crate只在

  • 未发出关闭信号且你等待(弱或强)守卫以确定是否取消时才会加锁;
  • 检查应用程序是否可以关闭通常会在收到关闭信号并释放所有(强)守卫之前加锁。

索引

示例

一个展示所有内容的示例

use std::time::Duration;
use tokio_graceful::Shutdown;

#[tokio::main]
async fn main() {
    // most users can just use `Shutdown::default()` to initiate
    // shutdown upon the default system signals.
    let signal = tokio::time::sleep(std::time::Duration::from_millis(100));
    let shutdown = Shutdown::new(signal);

    // you can use shutdown to spawn tasks that will
    // include a guard to prevent the shutdown from completing
    // aslong as these tasks are open
    shutdown.spawn_task(async {
        tokio::time::sleep(std::time::Duration::from_millis(10)).await;
    });
    // or spawn a function such that you have access to the guard coupled to the task
    shutdown.spawn_task_fn(|guard| async move {
        let guard2 = guard.clone();
        guard.cancelled().await;
    });

    // this guard isn't dropped, but as it's a weak guard
    // it has no impact on the ref count of the common tokens.
    let guard_weak = shutdown.guard_weak();

    // this guard needs to be dropped as otherwise the shutdown is prevented;
    let guard = shutdown.guard();
    drop(guard);

    // guards can be downgraded to weak guards, to not have it be counted any longer in the ref count
    let weak_guard_2 = shutdown.guard().downgrade();

    // guards (weak or not) are cancel safe
    tokio::select! {
        _ = tokio::time::sleep(std::time::Duration::from_millis(10)) => {},
        _ = weak_guard_2.into_cancelled() => {},
    }

    // you can also wait to shut down without any timeout limit
    // `shutdown.shutdown().await;`
    shutdown
        .shutdown_with_limit(Duration::from_secs(60))
        .await
        .unwrap();

    // once a shutdown is triggered the ::cancelled() fn will immediately return true,
    // forever, not just once. Even after shutdown process is completely finished.
    guard_weak.cancelled().await;

    // weak guards can be upgraded to regular guards to take into account for ref count
    let guard = guard_weak.upgrade();
    // even this one however will know it was cancelled
    guard.cancelled().await;
}

可运行示例

虽然上面的示例一次展示了此crate的所有部分,但可能需要看到示例,了解如何在类似生产环境的设置中使用此crate。这就是可运行示例的用途。

最好在设置了 RUST_LOG=trace 环境变量的情况下运行可运行示例,这样你就能看到 tokio-graceful 的详细日志,真正看到它在行动,并了解其工作方式,或者至少其流程。

examples/tokio_tcp.rs

RUST_LOG=trace cargo run --example tokio_tcp

tokio_tcp 示例展示了 tokio-graceful 关闭最初开发的原因,因为它使从开始到结束管理优雅关闭变得容易得多,而无需立即使用大型工具或提供超出所需的内容。

该示例运行一个tcp 'echo'服务器,你可以使用telnet与它交互: telnet 127.0.0.1 8080。由于你可以控制何时退出,因此你可以轻松地让它超时。

examples/hyper.rs

RUST_LOG=trace cargo run --example hyper

如果您希望将此库作为Hyper用户使用,可以使用与Tokio tcp示例几乎相同的方案。

此示例只有一个路由服务器函数,5秒后返回'hello'(200 OK)。延迟是为了让您看到优雅关闭的效果。

examples/hyper_panic.rs

RUST_LOG=trace cargo run --example hyper_panic

hyper示例相同,但展示了您如何确保通过自定义信号(在常规退出信号之上)手动触发关闭,例如,由于生成的任务由于错误、panic或没有任何信息而意外退出(可能是最糟糕的一种情况)。

如果您在循环中运行服务器之前也执行了设置操作,这一点尤为重要,因为这些通常是您的代码中进行假设和panic的部分。一个常见的例子是,如果选择的端口已被其他东西绑定,您会允许服务器(在任务内部创建和启动)panic。

另一种方法是使用tokio::select!在您的Shutdown::shutdown*未来以及所有关键任务句柄上。这将确保在意外退出场景中退出。然而,这意味着在这种情况下您将跳过优雅关闭,这就是为什么我们不推荐这种方法,因此在我们的示例代码中也没有使用该方法。

examples/waitgroup.rs

cargo run --example waitgroup

此示例展示了如何使用此crate创建Waitgroup,它允许您在不首先触发信号的情况下等待多个异步工作/任务。

如果您需要一个首先需要等待信号的waitgroup,您可以使用Shutdown::new创建一个常规的Shutdown实例来给出您的'触发'信号(一个未来)。

贡献

🎈 感谢您的帮助,使我们能够改进项目!我们很高兴您能加入我们!我们有一个贡献指南,帮助您参与tokio-graceful项目。

鸣谢

特别感谢Tokio生态系统,包括那些开发和维护Tokio Discord服务器的人。与他们的讨论和问答会议对项目的开发至关重要。Tokio的代码库也是展示可能性和良好实践的一个宝库。

在此背景下,还要特别感谢@tobz,他给了我从原子角度而不是直接使用通道解决方案来考虑这个问题的想法。

许可证

此项目同时受MIT许可证Apache 2.0许可证的许可。

贡献

除非您明确声明,否则您提交给tokio-graceful的任何贡献均应受MITApache 2.0的许可,不附加任何额外的条款或条件。

赞助商

tokio-graceful是完全免费、开源的软件,需要时间进行开发和维护。

通过成为赞助商来支持此项目。我们接受一次性付款,可在GitHub以及"Buy me a Coffee"上完成。

赞助商帮助我们持续维护和改进 tokio-graceful 以及其他自由和开源 (FOSS) 技术。它还帮助我们创建教育内容,例如 https://github.com/plabayo/learn-rust-101,以及其他开源库,如 https://github.com/plabayo/tower-async

赞助商将获得优惠,并根据您的定期贡献,您还可以依赖我们提供支持和咨询。

为开源贡献

我们从赞助商那里收到的部分资金用于资助我们依赖的其他项目。Plabayo 赞助以下组织和个人构建和维护 tokio-graceful 所依赖的开放源代码软件

名称 项目
💌 Tokio (Tokio,异步运行时)
💌 Sean McArthur (Tokio)

常见问题解答 (FAQ)

https://tokio.rs/tokio/topics/shutdown 的区别是什么?

https://tokio.rs/tokio/topics/shutdown 是 Tokio 开发者编写的一个优秀的教程。它旨在教导和启发你如何优雅地关闭 Tokio 驱动的应用程序,并给你一个大致的思路,了解何时使用它。

尽管如此,你完全可以将从该教程中学到的知识直接应用于你的生产应用程序。它会很好地工作。然而,你需要自己管理许多组件。

那么,关于 https://crates.io/ 上提供优雅关闭的其他 crate 是什么?

它们工作得很好,使用起来也和这个 crate 一样简单。然而,我们认为这些 crate 提供了比典型用例所需更多的功能,因此表面和内部机制都更复杂。

如何在任务内部触发关闭?

你可以通过向 Shutdown::new 提供“信号”来自定义机制来实现这一点。例如,你可以通过使用 https://docs.rs/tokio/latest/tokio/sync/struct.Notify.html 来轻松实现这一点,这样你就可以在任何你希望通知的任务中通知信号,并且你的信号是 https://docs.rs/tokio/latest/tokio/sync/struct.Notify.html#method.notified

然而,这并不是我们遇到的情况,因为大多数网络服务(无论是服务器还是代理)通常希望所有连接都独立运行,而没有关键故障。在这种环境中,不需要自上而下的取消机制。因此,我们没有内置任何功能,这使得我们可以保持 API 和源代码更简单,而且还可以在未来自由更改一些内部细节,而不必继续支持这个用例。

与此相关的是,你可能想在某个关键后台任务退出(无论是否有错误)的情况下提前退出,例如你的服务器任务。有关如何做到这一点的示例,请参阅 examples/hyper_panic.rs。同样的方法也适用于从任务内部关闭,只是你可能使用 notify 而不是 oneshot,或者类似的东西。

你能制作一个视频解释你为什么制作这个 crate,如何使用它以及它是如何工作的吗?

当然可以。您可以在我们的 Rust 101 视频播放列表中找到 VOD:[https://www.youtube.com/watch?v=GAkOJgrE3CQ](https://www.youtube.com/watch?v=GAkOJgrE3CQ),该播放列表的地址是:[https://www.youtube.com/watch?v=EngAlbv2y98&list=PLQgXEsLXFxpVyLddG8FFXfNQEiodTzAjj](https://www.youtube.com/watch?v=EngAlbv2y98&list=PLQgXEsLXFxpVyLddG8FFXfNQEiodTzAjj)

你想学习Rust还是提高你的Rust知识水平?

查看https://rust-lang.guide/,看看它是否能帮助你在这个旅程中。

依赖项

~3–31MB
~448K SLoC