问题
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 Core
s. 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