“cannot recursively call into `Core`” when trying to achieve nested concurrency using Tokio

痞子三分冷 提交于 2021-01-28 04:12:09

问题


I'm building a service that periodically makes an HTTP request. I'm using tokio::timer::Delay as a periodic trigger and hyper to make the HTTP call.

Using them together gives me the following error:

thread 'tokio-runtime-worker-1' panicked at 'cannot recursively call into `Core`', libcore/option.rs:960:5

How can I make this work?

Below is a simplified version of the service.

main.rs

extern crate futures;
extern crate hyper;
extern crate tokio;
extern crate tokio_core;
extern crate tokio_timer;

use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;

use std::time::{Duration, Instant};
use tokio::timer::Delay;
use std::io::{self, Write};

fn main() {
    let when = Instant::now() + Duration::from_secs(1);

    tokio::run({
        Delay::new(when)
            .map_err(|e| panic!("timer failed; err={:?}", e))
            .and_then(move |_| {
                let mut core = Core::new().unwrap();
                let client = Client::new(&core.handle());

                let uri = "http://httpbin.org/ip".parse().unwrap();
                let work = client.get(uri).and_then(|res| {
                    println!("Response: {}", res.status());

                    res.body()
                        .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from))
                });
                core.run(work).unwrap();
                Ok(())
            })
    })
}

Cargo.toml

[dependencies]
futures = "0.1"
hyper = "0.11"
tokio-core = "0.1"
tokio-timer = "0.1"
tokio = "0.1"
serde = "1.0.19"
serde_derive = "1.0.19"
serde_json = "1.0.19"
hyper-tls = "0.1.3"

回答1:


One primary conceptual issue I see is that you should not be creating arbitrary Cores. You want to share these as much as possible because that's how Tokio communicates between different futures.

Creating a single core and using it for the HTTP request and the overall command is the right thing to do.

hyper 0.11

hyper 0.11 is not compatible with the tokio crate. Instead, you need to use the component pieces of Tokio:

extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate tokio_timer;

use futures::{Future, Stream};
use hyper::Client;
use std::{
    io::{self, Write}, time::{Duration, Instant},
};
use tokio_core::reactor::Core;
use tokio_timer::Delay;

fn main() {
    let when = Instant::now() + Duration::from_secs(1);

    let mut core = Core::new().expect("Could not achieve criticality");
    let handle = core.handle();

    let command = Delay::new(when)
        .map_err(|e| panic!("timer failed; err={:?}", e))
        .and_then(move |_| {
            let client = Client::new(&handle);

            let uri = "http://httpbin.org/ip".parse().unwrap();
            client.get(uri).and_then(|res| {
                println!("Response: {}", res.status());

                res.body()
                    .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from))
            })
        });

    core.run(command).expect("Meltdown occurred");
}
[dependencies]
futures = "0.1"
hyper = "0.11.27"
tokio-core = "0.1.17"
tokio-timer = "0.2.3"

hyper 0.12

Using hyper 0.12, it looks like this:

extern crate hyper;
extern crate tokio;

use hyper::Client;
use std::{
    error::Error, io::{self, Write}, time::{Duration, Instant},
};
use tokio::{
    prelude::{Future, Stream}, timer::Delay,
};

type MyError = Box<Error + Send + Sync>;

fn main() {
    let when = Instant::now() + Duration::from_secs(1);

    let command = Delay::new(when).from_err::<MyError>().and_then(move |_| {
        let client = Client::new();

        let uri = "http://httpbin.org/ip".parse().unwrap();
        client.get(uri).from_err::<MyError>().and_then(|res| {
            println!("Response: {}", res.status());

            res.into_body()
                .from_err::<MyError>()
                .for_each(|chunk| io::stdout().write_all(&chunk).map_err(From::from))
        })
    });

    tokio::run(command.map_err(|e| panic!("Error: {}", e)));
}
[dependencies]
hyper = "0.12.0"
tokio = "0.1.6"


来源:https://stackoverflow.com/questions/50644880/cannot-recursively-call-into-core-when-trying-to-achieve-nested-concurrency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!