salvo-rs / salvo

A powerful web framework built with a simplified design.
https://salvo.rs
Apache License 2.0
2.92k stars 172 forks source link

Tokio runtime panic when using QuinnListener #817

Closed markcda closed 2 weeks ago

markcda commented 2 weeks ago

Describe the bug thread 'tokio-runtime-worker' panicked

To Reproduce Steps to reproduce the behavior:

  1. Make little server on QuinnListener
  2. Access to it via HTTP/3-supported browser or curl
  3. Get this error:
thread 'tokio-runtime-worker' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.38.0/src/runtime/scheduler/multi_thread/mod.rs:86:9:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.

With RUST_BACKTRACE=full still found not so much useful information:

backend-1  | thread 'tokio-runtime-worker' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.38.0/src/runtime/scheduler/multi_thread/mod.rs:86:9:
backend-1  | Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
backend-1  | stack backtrace:
backend-1  |    0:     0x57f11fdfb5d5 - std::backtrace_rs::backtrace::libunwind::trace::hd0a431ec4286eec2
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/../../backtrace/src/backtrace/libunwind.rs:116:5
backend-1  |    1:     0x57f11fdfb5d5 - std::backtrace_rs::backtrace::trace_unsynchronized::h55b7147bbdcae103
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
backend-1  |    2:     0x57f11fdfb5d5 - std::sys::backtrace::_print_fmt::h5ba811d5fa76665c
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/sys/backtrace.rs:68:5
backend-1  |    3:     0x57f11fdfb5d5 - <std::sys::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hc7ed570e71131300
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/sys/backtrace.rs:44:22
backend-1  |    4:     0x57f11fe289bb - core::fmt::rt::Argument::fmt::hd5f04252949343fb
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/core/src/fmt/rt.rs:165:63
backend-1  |    5:     0x57f11fe289bb - core::fmt::write::h525edfe35df838b2
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/core/src/fmt/mod.rs:1168:21
backend-1  |    6:     0x57f11fdf7bff - std::io::Write::write_fmt::h7ca43b42bd752649
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/io/mod.rs:1835:15
backend-1  |    7:     0x57f11fdfb3ae - std::sys::backtrace::_print::h5374f6e608e081ce
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/sys/backtrace.rs:47:5
backend-1  |    8:     0x57f11fdfb3ae - std::sys::backtrace::print::ha7453f9fb23375ba
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/sys/backtrace.rs:34:9
backend-1  |    9:     0x57f11fdfc729 - std::panicking::default_hook::{{closure}}::hf9505cfe32528ed7
backend-1  |   10:     0x57f11fdfc4cc - std::panicking::default_hook::ha7962b8515cde474
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/panicking.rs:292:9
backend-1  |   11:     0x57f11fdfccb1 - std::panicking::rust_panic_with_hook::hea4c878dc07df55b
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/panicking.rs:796:13
backend-1  |   12:     0x57f11fdfcae3 - std::panicking::begin_panic_handler::{{closure}}::hca858b01da723ad6
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/panicking.rs:663:13
backend-1  |   13:     0x57f11fdfba99 - std::sys::backtrace::__rust_end_short_backtrace::h94b285c94ce95409
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/sys/backtrace.rs:171:18
backend-1  |   14:     0x57f11fdfc7f4 - rust_begin_unwind
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/std/src/panicking.rs:661:5
backend-1  |   15:     0x57f11fe25853 - core::panicking::panic_fmt::h47b1e0ddaafb858d
backend-1  |                                at /rustc/bcf94dec5ba6838e435902120c0384c360126a26/library/core/src/panicking.rs:74:14
backend-1  |   16:     0x57f11ea4420e - tokio::runtime::context::runtime::enter_runtime::h964a40d550a5e753
backend-1  |                                at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.38.0/src/runtime/context/runtime.rs:68:5
backend-1 exited with code 139

Expected behavior Handler should be executed. At least, it works as expected when using HTTP/2, HTTP/1.1.

Desktop (please complete the following information):

chrislearn commented 2 weeks ago

Can you run the hello-h3 example normally? From the error, it seems that you have blocked the main thread of tokio, which is a problem with your code.

markcda commented 2 weeks ago

Can you run the hello-h3 example normally? From the error, it seems that you have blocked the main thread of tokio, which is a problem with your code.

Well, hello-h3 runs normally.

With log's help I found that the bug is rising when I try parse JSON from request (let data = req.parse_json::<MyData>().await?;

chrislearn commented 2 weeks ago

Please provide the minimal reproducible code。

markcda commented 2 weeks ago

Code

main.rs:

use salvo::conn::rustls::{Keycert, RustlsConfig};
use salvo::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct SignInRequestData {
    pub login: String,
    pub password: String,
}

#[handler]
async fn login(req: &mut Request, res: &mut Response) {
    let data = req.parse_json::<SignInRequestData>().await.unwrap();
    res.render(format!("Logged in as {}", data.login));
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();
    let cert = include_bytes!("../certs/cert.pem").to_vec();
    let key = include_bytes!("../certs/key.pem").to_vec();

    let router = Router::new().post(login);
    let config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));
    let listener = TcpListener::new(("0.0.0.0", 5800)).rustls(config.clone());

    let acceptor = QuinnListener::new(config.build_quinn_config().unwrap(), ("0.0.0.0", 5800))
        .join(listener)
        .bind()
        .await;

    Server::new(acceptor).serve(router).await;
}

Cargo.toml:

[package]
name = "example-hello-h3"
version.workspace = true
edition.workspace = true
publish.workspace = true

[dependencies]
salvo = { workspace = true, features = ["quinn"] }
serde = { version = "1", features = ["derive"] }
tokio = { workspace = true, features = ["macros"] }
tracing.workspace = true
tracing-subscriber.workspace = true

Usage

cd examples && cargo run --bin example-hello-h3

And doing request with curl:

curl --request POST --http3-only --tlsv1.3 -H "Content-Type: application/json" --data '{"login":"xyz","password":"xyz"}' https://localhost:5800 --verbose

We're getting:

* upload completely sent off: 32 bytes
* HTTP/3 stream 0 was closed cleanly, but before getting all response header fields, treated as error
* Connection #0 to host localhost left intact
curl: (95) error:8000006F:system library::Connection refused
markcda commented 2 weeks ago

And:

thread 'tokio-runtime-worker' panicked at /home/titoffklim/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.38.0/src/runtime/scheduler/multi_thread/mod.rs:86:9:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
markcda commented 2 weeks ago

As long as HTTP/2 connection looks like this:

curl --request POST -H "Content-Type: application/json" --data '{"login":"xyz","password":"xyz"}' https://localhost:5800 --verbose
< HTTP/2 200 
< alt-svc: h3=":5800"; ma=2592000,h3-29=":5800"; ma=2592000
< content-type: text/plain; charset=utf-8
< date: Mon, 24 Jun 2024 06:36:56 GMT
< content-length: 16
< 
* Connection #0 to host localhost left intact
Logged in as xyz