Home > database >  Kill warp webserver on request in rust
Kill warp webserver on request in rust

Time:06-14

I'm learning rust and for something that I want to do is kill, or shutdown, a webserver on GET /.

Is this something you can't do in with warp? Or is my implementation broken?

I've got the following code, but it just doesn't seem to want to respond to any HTTP requests.

pub async fn perform_oauth_flow(&self) {
        let (tx, rx) = channel::unbounded();

        let routes = warp::path::end().map(move || {
            println!("handling");
            tx.send("kill");
            Ok(warp::reply::with_status("OK", http::StatusCode::CREATED))
        });

        println!("Spawning server");
        let webserver_thread = thread::spawn(|| async {
            spawn(warp::serve(routes).bind(([127, 0, 0, 1], 3000)))
                .await
                .unwrap();
        });

        println!("waiting for result");
        let result = rx.recv().unwrap();
        println!("Got result");
        if result == "kill" {
            webserver_thread.join().unwrap().await;
        }
    }

CodePudding user response:

let webserver_thread = thread::spawn(|| async {
//                                      ^^^^^

Creating an async block is not going to execute the code inside; it is just creating a Future you need to .await. Your server never actually runs.

In general, using threads with async code is not going to work well. Better to use your runtime tasks, in case of warp it is tokio, using tokio::spawn():

let webserver_thread = tokio::spawn(async move {
    spawn(warp::serve(routes).bind(([127, 0, 0, 1], 3000)))
        .await
        .unwrap();
});

// ...

if result == "kill" {
    webserver_thread.await;
}

You may also find it necessary to use tokio's async channels instead of synchronous channels.

CodePudding user response:

There are two issues in your code:

  1. As pointed out by @ChayimFriedman's answer, you never start the server because your async block never runs.
  2. Even if you replace the threads with Tokio tasks, you never tell the server to exit. You need to use bind_with_graceful_shutdown so that you can notify the server to exit.

(Untested) complete example:

pub async fn perform_oauth_flow(&self) {
    let (tx, rx) = tokio::oneshot::channel();

    let routes = warp::path::end().map(move || {
        println!("handling");
        tx.send(());
        Ok(warp::reply::with_status("OK", http::StatusCode::CREATED))
    });

    println!("Spawning server");
    let server = warp::serve(routes)
               .bind_with_graceful_shutdown(
                   ([127, 0, 0, 1], 3000)),
                   async { rx.await.ok(); })
               .1;

    println!("waiting for result");
    server.await;
}
  • Related