1
// src/server.rs
use axum::{
    extract::Path,
    response::{IntoResponse, Response},
    routing::get,
};

pub struct Server {}

impl Server {
    pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
        let axum_http_make_service = axum::Router::new()
            .route("/:sec", get(wait_sec_event))
            .into_make_service();
        let http_server =
            axum::Server::bind(&"0.0.0.0:4000".parse().unwrap()).serve(axum_http_make_service);

        let http_handle = tokio::spawn(http_server);
        let _ = tokio::try_join!(http_handle)?;

        Ok(())
    }
}

async fn wait_sec_event(Path(sec): Path<String>) -> Response {
    let a = std::time::Duration::from_secs(sec.parse::<u64>().unwrap());
    std::thread::sleep(a);
    "yo".into_response()
}
// src/app.rs
use std::net::SocketAddr;

use crate::server;

pub struct App {
    port: SocketAddr,
}

impl App {
    pub fn new(p: SocketAddr) -> Self {
        Self { port: p }
    }
    pub async fn run(self) -> Result<(), Box<dyn std::error::Error>> {
        server::Server::run().await
    }
}
// src/main.rs
use std::net::SocketAddr;

use app::App;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // build our application with a single route
    let app = App::new(SocketAddr::from(([0, 0, 0, 0], 4000)));
    app.run().await
}

pub mod app;
pub mod server;

When I tried to implement a axum server I found that if I put axum::Server::bind(&"0.0.0.0:4000".parse().unwrap()).serve(axum_http_make_service); into tokio::spawn instead of just await.unwrap() it

the server just can't accept requests in parallel.

means if I do curl 127.0.0.1:4000/10 then curl 127.0.0.1:4000/3 ,

the later request won't execute until the first one is finished This won't happen if I just await.unwrap() it.

Any idea where I might make a mistake?

ron
  • 11
  • 2

1 Answers1

3

You use std::thread::sleep, blocking the thread, which you shouldn't do in an async environment because it can prevent other tasks on the same thread to run like you experienced. Use tokio::time::sleep instead:

async fn wait_sec_event(Path(sec): Path<String>) -> Response {
    let a = std::time::Duration::from_secs(sec.parse::<u64>().unwrap());
    tokio::time::sleep(a).await;
    "yo".into_response()
}

I believe the difference in behaviour is because more or less by chance the tasks get spawned on different threads in your directly awaiting scenario while they get spawned on the same thread when using tokio::spawn.

cafce25
  • 15,907
  • 4
  • 25
  • 31