Search code examples
multithreadingrust

Kill warp webserver on request in rust


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;
        }
    }

Solution

  • 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.