宣布 async-backtrace

October 27, 2022

今天,我们很高兴宣布 async-backtrace 的首次发布,这是一个 crate,使您能够有效地跟踪和查看应用程序中异步任务的状态。

在同步、多线程应用程序中,您可以通过检查所有运行线程的堆栈跟踪来调查死锁。不幸的是,这种方法对于大多数异步 Rust 应用程序来说都失效了,因为挂起的任务(即未被主动轮询的任务)对于传统的堆栈跟踪是不可见的。async-backtrace crate 填补了这一空白,使您能够看到这些隐藏任务的状态。它的架构设计为高效且无需配置,并且适合在生产环境中部署。

这个 crate 补充了(但尚未与)tracing 库和 tokio-console 集成。使用 async-backtrace 可以鸟瞰应用程序中的任务状态,并使用 tracing 来隔离导致该状态的输入。如果您的应用程序使用 tokio 运行时,则可以使用 tokio-console 来更深入地了解您的应用程序与 tokio 同步原语的交互。

开始使用

要使用 async-backtrace,首先将该 crate 添加到您的 Cargo.toml 文件中

[dependencies]
async-backtrace = "0.2"

然后,要将您的 async fn 包含在异步任务跟踪中,只需使用 #[async_backtrace::framed] 注释它们,并调用 taskdump_tree 以接收应用程序任务的漂亮打印树。例如

#[tokio::main(flavor = "current_thread")]
async fn main() {
    tokio::select! {
        // run the following branches in order of their appearance
        biased;

        // spawn task #1
        _ = tokio::spawn(foo()) => { unreachable!() }

        // spawn task #2
        _ = tokio::spawn(foo()) => { unreachable!() }

        // print the running tasks
        _ = tokio::spawn(async {}) => {
            println!("{}", async_backtrace::taskdump_tree(true));
        }
    };
}

#[async_backtrace::framed]
async fn foo() {
    bar().await;
}

#[async_backtrace::framed]
async fn bar() {
    baz().await;
}

#[async_backtrace::framed]
async fn baz() {
    std::future::pending::<()>().await
}

运行上面的示例会打印树

╼ multiple::foo::{{closure}} at backtrace/examples/multiple.rs:22:1
  └╼ multiple::bar::{{closure}} at backtrace/examples/multiple.rs:27:1
     └╼ multiple::baz::{{closure}} at backtrace/examples/multiple.rs:32:1
╼ multiple::foo::{{closure}} at backtrace/examples/multiple.rs:22:1
  └╼ multiple::bar::{{closure}} at backtrace/examples/multiple.rs:27:1
     └╼ multiple::baz::{{closure}} at backtrace/examples/multiple.rs:32:1

点击这里查看更多示例!

欢迎反馈

这次发布只是一个初始版本。async-backtrace 的工作才刚刚开始。为了指导我们的开发,我们需要您的反馈。所以,请试用一下,并告诉我们效果如何。请提交 issue 并在 Discord 上 ping 我们

— Jack Wrenn (@jswrenn)