如何在完成一个请求后终止超级服务器?

How do I terminate a hyper server after fulfilling one request?

我需要一个简单的超级服务器来处理单个请求然后退出。到目前为止,这是我的代码,我相信我所需要的只是一种将 tx 转换为 hello 的方法,这样我就可以使用 tx.send(()) 并且它应该按照我想要的方式工作。但是,如果不让编译器对我大喊大叫,我无法找到一种方法来做到这一点。

use std::convert::Infallible;

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};

async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new(Body::from("Hello World!")))
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {

    let (tx, rx) = tokio::sync::oneshot::channel::<()>();

    let make_svc = make_service_fn(|_conn| {
        async { Ok::<_, Infallible>(service_fn(hello)) }
    });

    let addr = ([127, 0, 0, 1], 3000).into();

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

    println!("Listening on http://{}", addr);

    let graceful = server.with_graceful_shutdown(async {
        rx.await.ok();
    });

    graceful.await?;

    Ok(())
}

Rust playground

相关板条箱:

tokio = { version = "0.2", features = ["full"] }
hyper = "0.13.7"

and , the hyper API has changed and I am unable to compile the code when edited to work with the current version.

一个简单的解决方案是为此使用全局状态,通过 tokio 的 Mutex 类型实现,如下所示:

use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use lazy_static::lazy_static;
use std::convert::Infallible;
use std::sync::Arc;
use tokio::sync::oneshot::Sender;
use tokio::sync::Mutex;

lazy_static! {
    /// Channel used to send shutdown signal - wrapped in an Option to allow
    /// it to be taken by value (since oneshot channels consume themselves on
    /// send) and an Arc<Mutex> to allow it to be safely shared between threads
    static ref SHUTDOWN_TX: Arc<Mutex<Option<Sender<()>>>> = <_>::default();
}

async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    // Attempt to send a shutdown signal, if one hasn't already been sent
    if let Some(tx) = SHUTDOWN_TX.lock().await.take() {
        let _ = tx.send(());
    }

    Ok(Response::new(Body::from("Hello World!")))
}

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let (tx, rx) = tokio::sync::oneshot::channel::<()>();
    SHUTDOWN_TX.lock().await.replace(tx);

    let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(hello)) });

    let addr = ([127, 0, 0, 1], 3000).into();

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

    println!("Listening on http://{}", addr);

    let graceful = server.with_graceful_shutdown(async {
        rx.await.ok();
    });

    graceful.await?;

    Ok(())
}

在这个版本的代码中,我们将关闭信号通道的发送者一半存储在一个受互斥锁保护的全局变量中,然后尝试使用该通道在每次请求时发送信号。