我正在Rust中编写一个带有warp的服务。当服务收到SIGTERM信号时,我希望它能正常关闭,并可能进行一些日志记录或其他工作。
我试了很多例子,但都不起作用。最有希望的似乎来自这个问题,但我似乎无法让它发挥作用,甚至无法编译。我怀疑这个问题得到答复后,情况发生了变化。
# Cargo.toml
[dependencies]
tokio = {version = "1", features = ["full"]}
warp = "0.3"
futures = "0.3"
//! main.rs
use warp::Filter;
use futures;
fn main() {
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::run(futures::future::lazy(move || {
let routes = warp::any().map(|| "Hello, World!");
let (_, server) = warp::serve(routes)
.bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), rx);
warp::spawn(server);
}));
println!("Exiting!");
}
error[E0425]: cannot find function `run` in crate `tokio`
--> src/main.rs:6:12
|
6 | tokio::run(futures::future::lazy(move || {
| ^^^ not found in `tokio`
error[E0425]: cannot find function `spawn` in crate `warp`
--> src/main.rs:10:15
|
10 | warp::spawn(server);
| ^^^^^ not found in `warp`
|
help: consider importing one of these items
|
1 | use std::thread::spawn;
|
1 | use tokio::spawn;
|
error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
--> src/main.rs:6:16
|
6 | tokio::run(futures::future::lazy(move || {
| ^^^^^^^^^^^^^^^^^^^^^ ------- takes 0 arguments
| |
| expected closure that takes 1 argument
|
help: consider changing the closure to take and ignore the expected argument
|
6 | tokio::run(futures::future::lazy(move |_| {
| ~~~
error[E0271]: type mismatch resolving `<tokio::sync::oneshot::Receiver<_> as warp::Future>::Output == ()`
--> src/main.rs:9:14
|
9 | .bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), rx);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Result`
|
= note: expected unit type `()`
found enum `Result<_, tokio::sync::oneshot::error::RecvError>`
note: required by a bound in `warp::Server::<F>::bind_with_graceful_shutdown`
--> /Users/stephen.gibson/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.3.2/src/server.rs:281:29
|
281 | signal: impl Future<Output = ()> + Send + 'static,
| ^^^^^^^^^^^ required by this bound in `warp::Server::<F>::bind_with_graceful_shutdown`
如有任何建议或更好的更新代码,我们将不胜感激。
感谢大家的想法。这是最终按照我想要的方式工作的代码:
use warp::Filter;
use tokio::signal::unix::{signal, SignalKind};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let routes = warp::any().map(|| "Hello, World!");
let mut stream = signal(SignalKind::terminate())?;
let (_, server) = warp::serve(routes)
.bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async move {
println!("waiting for signal");
stream.recv().await;
println!("done waiting for signal");
});
match tokio::join!(tokio::task::spawn(server)).0 {
Ok(()) => println!("serving"),
Err(e) => println!("ERROR: Thread join error {}", e)
};
println!("terminating");
Ok(())
}
一个更简单的解决方案,使用tokio::signal::ctrl_c
,这是一个专门设计用于睡眠直到收到关闭信号的函数。
它既适用于Unix,也适用于Windows。
use warp::Filter;
#[tokio::main]
async fn main() {
let routes = warp::any().map(|| "Hello, World!");
let (_addr, fut) = warp::serve(routes)
.bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async move {
tokio::signal::ctrl_c()
.await
.expect("failed to listen to shutdown signal");
});
fut.await;
println!("shutting down");
}
以下是有效的示例代码。bind_with_graceful_shutdown 的包装文档给了我灵感
use tokio::sync::oneshot;
use warp::Filter;
#[tokio::main]
async fn main() {
let routes = warp::any().map(|| "Hello, World!");
let (tx, rx) = oneshot::channel();
let (_addr, server) =
warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 3030), async {
rx.await.ok();
});
// Spawn the server into a runtime
tokio::task::spawn(server);
// Later, start the shutdown...
let _ = tx.send(());
}