-1

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Tim Ross
  • 19
  • 3
  • You *must* add tokio as an explicit dependency and create a runtime for warp to use, warp requires an active tokio runtime to be scheduled on, even if you don't want to async-ify `main` (which… why?). You can see the tokio docs or just dump a macro-expanded warp hello-world to see how to initialise a tokio runtime if you absolutely don't want to use `tokio::main` (which, again, why?) – Masklinn Apr 27 '21 at 14:40
  • 1
    This is not a Tokio version mismatch. This is a mismatch between Tokio executor expected by Warp and the executor provided by `futures::block_on`. – Cerberus Apr 27 '21 at 14:42

1 Answers1

2

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"] }
sebpuetz
  • 2,430
  • 1
  • 7
  • 15
  • *there is no runtime to execute the futures on* — that can't possibly be correct. If there is async code that is running, there is a runtime present. – Shepmaster Apr 27 '21 at 15:23
  • In OPs example there was no async code being executed as there was no runtime available, thus the panic? – sebpuetz Apr 27 '21 at 15:24
  • *Some* async code was being executed — that which panicked. [Cerberus was correct](https://stackoverflow.com/questions/67284898/how-do-i-spawn-a-thread-inside-of-warp-to-handle-async-behavior#comment118931225_67284898) (and was correct [a year ago](https://stackoverflow.com/a/59764528/155423)) — the problem is that you can't execute those specific futures on the future's executor. – Shepmaster Apr 27 '21 at 15:32
  • The panic originates [here](https://github.com/tokio-rs/tokio/blob/master/tokio/src/runtime/context.rs#L18) and is quite literally caused by no tokio runtime being present, what is `future`'s executor supposed to be? The `futures` crate is runtime agnostic, no? So, am I misunderstanding something you're saying or did I get something else wrong? – sebpuetz Apr 27 '21 at 16:00
  • 1
    That panic can only be executed if *some* async executor has driven the code that far. The Futures crate has a lot of features; `futures::executor::block_on` is an executor / runtime, but it doesn’t have the ability to run those specific Tokio futures. – Shepmaster Apr 27 '21 at 16:11
  • Thanks for the explanation, I had an incorrect understanding of the `futures` crate and execoturs then! – sebpuetz Apr 27 '21 at 16:30
  • 1
    Thanks for answer and for everyone who commented! You are right that I was missing the runtime. With that change it seems to work as expected. – Tim Ross Apr 27 '21 at 17:21