В моем понимании того, как работает hyper
, было довольно много ошибок.В основном:
- если служба должна обрабатывать фьючерсы, не используйте
service_fn_ok
для ее создания (она предназначена для синхронных служб): используйте service_fn
; - не используйте
wait
: все фьючерсы используют одного и того же исполнителя, исполнение будет зависать вечно (в документах есть предупреждение, ну да ладно ...); - в качестве уведомлений ecstaticm0rse,
hyper::rt::spawn
может использоваться длячитать статистику асинхронно, вместо того, чтобы делать это в службе
Требуется ли Токио для Shiplift?
Да.Он использует hyper
, который выдает executor failed to spawn task
, если по умолчанию tokio
исполнитель недоступен (работа с фьючерсами почти всегда требует исполнителя).
Вот минимальная версия того, с чем я закончил(Токио 0,1.20 и гипер 0,12):
use std::net::SocketAddr;
use std::time::{Duration, Instant};
use tokio::prelude::*;
use tokio::timer::Interval;
use hyper::{
Body, Response, service::service_fn_ok,
Server, rt::{spawn, run}
};
fn init_background_task(swarm_name: String) -> impl Future<Item = (), Error = ()> {
Interval::new(Instant::now(), Duration::from_secs(1))
.map_err(|e| panic!(e))
.for_each(move |_instant| {
futures::future::ok(()) // unimplemented: call shiplift here
})
}
fn init_server(address: SocketAddr) -> impl Future<Item = (), Error = ()> {
let service = move || {
service_fn_ok(|_request| Response::new(Body::from("unimplemented")))
};
Server::bind(&address)
.serve(service)
.map_err(|e| panic!("Server error: {}", e))
}
fn main() {
let background_task = init_background_task("swarm_name".to_string());
let server = init_server(([127, 0, 0, 1], 9898).into());
run(hyper::rt::lazy(move || {
spawn(background_task);
spawn(server);
Ok(())
}));
}