How do I spawn a thread inside of Warp to handle async behavior?

1k views Asked by At

I am using the Warp crate for a web service, but I am having problems getting it running from my non-async main.

I have tried several ways and the closest I have gotten is this:

Cargo.toml

[dependencies]
warp = "0.3"
futures = "0.3"

Code:

use std::collections::HashMap;
use std::thread::{sleep, spawn};
use std::time;
use warp::{Filter};
use futures::executor::block_on;

async fn get_ap_list() -> Result<impl warp::Reply, warp::Rejection> {
    let mut result = HashMap::new();

    // TODO: Get a full list
    result.insert("SSID", "rossless_24");

    Ok(warp::reply::json(&result))
}

async fn start_ap_server() {
    println!("AP server");

    let get_ap = warp::get()
        .and(warp::path("ap"))
        .and(warp::path("list"))
        .and(warp::path::end())
        .and_then(get_ap_list);

    warp::serve(get_ap)
       .run(([0, 0, 0, 0], 3030))
        .await;
}

// This intermediate function seem a bit redundant but I can't seem to spawn the async server directly
fn init_ap_server() {
    println!("Init AP server");

    let future = start_ap_server();
    block_on(future);
}

fn main() {
    let _t1 = spawn(move || {
        init_ap_server()
        });

    // Make sure main is still running
    loop {
        println!("Alive for test.");
        sleep(time::Duration::from_millis(5000));
    }
}

That seems to work but I get:

thread '<unnamed>' panicked at 'there is no reactor running, must be called from the context of a Tokio 1.x runtime', /home/tross/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.5.0/src/runtime/context.rs:18:26

Googling around I see that it is probably a Tokio version mismatch, but I don't even have Tokio in my dependencies, I am getting it from Warp.

Taking a step back, is there a simpler way to get what I want? I just want to launch some async code running (probably on its own thread) while leaving main alive and happy.

1

There are 1 answers

7
sebpuetz On

warp itself does pull in the tokio dependency but it does not come with the rt feature:

// warp/Cargo.toml
...
tokio = { version = "1.0", features = ["fs", "sync", "time"] }
...

So there is no runtime to execute the futures on. In order to get a tokio::Runtime you can explicitly spawn a Runtime and call block_on on that runtime:

// This intermediate function seem a bit redundant but I can't seem to spawn the async server directly
fn init_ap_server() {
    println!("Init AP server");
    let runtime = Builder::new_current_thread()
        .enable_io()
        .build()
        .expect("Failed to create runtime");

    let future = start_ap_server();
    runtime.block_on(future);
}

with:

[dependencies]
warp = "0.3"
tokio = {version = "1", features = ["rt"] }