【问题标题】:How do I terminate a hyper server after fulfilling one request?完成一个请求后如何终止超级服务器?
【发布时间】:2020-08-26 13:51:53
【问题描述】:

我需要一个简单的超级服务器来处理单个请求然后退出。到目前为止,这是我的代码,我相信我需要的只是一种将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"

自从How to share mutable state for a Hyper handler?How to share mutable state for a Hyper handler?之后,hyper API变了,我是unable to compile the code when edited to work with the current version

【问题讨论】:

  • 那么我们怎么能猜出编译器在喊什么?
  • playground中也能正常工作
  • @AlexLarionov @Shepmaster 当前代码没有错误。我在问如何完成某事,即如何在 hello 方法中使用 tx.send() 。我无法发布完整的错误消息,没有错误消息。我的代码也是完整的,没有我没有提到的其他类型、特征或字段,所有use 都存在,所有板条箱都是最新版本。我已使用您要求的其他详细信息编辑了帖子。

标签: rust hyper


【解决方案1】:

一个简单的解决方案是为此使用全局状态,这可以通过 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(())
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 2021-03-22
    • 1970-01-01
    相关资源
    最近更新 更多