如何从超级服务器使用Rust Shiplift

时间:2019-05-10 16:59:45

标签: rust rust-tokio

我正在尝试编写一个简单的Rust程序,该程序使用P0934读取Docker统计信息,并使用shiplift将其作为Prometheus指标公开。

shiplift统计信息示例本身可以正常运行,我正尝试将其集成到服务器中

fn handle(_req: Request<Body>) -> Response<Body> {
    let docker = Docker::new();
    let containers = docker.containers();
    let id = "my-id";
    let stats = containers
        .get(&id)
        .stats().take(1).wait();
    for s in stats {
        println!("{:?}", s);
    }
    // ...
}

// in main
let make_service = || {
    service_fn_ok(handle)
};

let server = Server::bind(&addr)
    .serve(make_service);

但似乎流永远挂起(我无法产生任何错误消息)。

我还在rust-prometheus中尝试了相同的重构(使用takewait而不是tokio::run),但是在这种情况下,我得到了错误{{ 1}}。 executor failed to spawn task: tokio::spawn failed (is a tokio runtime running this future?)是否需要tokio

编辑: 如果我已正确理解,我的尝试将不起作用,因为shiplift将阻止wait执行程序,而tokio将永远不会产生结果。

2 个答案:

答案 0 :(得分:0)

conda install -c conda-forge opencv的API是异步的,这意味着shiplift和其他函数将返回wait(),而不是阻塞主线程直到结果准备就绪。 Future实际上不会执行任何I / O,直到将其传递给执行者。如您所链接的示例一样,您需要将Future传递给Future。您应该阅读tokio docs,以更好地了解如何在rust中编写异步代码。

答案 1 :(得分:0)

在我对hyper的工作方式的理解中有很多错误。基本上:

  • 如果服务应处理期货,请不要使用service_fn_ok来创建它(这是用于同步服务):请使用service_fn;
  • 不要使用wait:所有期货都使用相同的执行器,执行将永远挂起(文档中有警告,但很好...);
  • 正如ecstaticm0rse所注意到的,hyper::rt::spawn可用于异步读取统计信息,而不是在服务中完成
  

船舶运输需要东京吗?

是的。它使用hyper,如果默认的executor failed to spawn task执行程序不可用(使用期货几乎总是需要执行程序),则会抛出tokio

这是我最终的最低版本(tokio 0.1.20和hyper 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(())
    }));
}