gpt4 book ai didi

asynchronous - 如何优雅地关闭 Tokio 运行时以响应 SIGTERM?

转载 作者:行者123 更新时间:2023-11-29 07:50:24 30 4
gpt4 key购买 nike

我有一个 main 函数,我在其中创建了一个 Tokio 运行时并在其上运行两个 futures。

use tokio;

fn main() {
let mut runtime = tokio::runtime::Runtime::new().unwrap();

runtime.spawn(MyMegaFutureNumberOne {});
runtime.spawn(MyMegaFutureNumberTwo {});

// Some code to 'join' them after receiving an OS signal
}

如何接收 SIGTERM,等待所有未完成的任务(NotReady)并退出应用程序?

最佳答案

处理信号很棘手,解释如何处理所有可能的情况过于宽泛。信号的实现不是跨平台标准的,所以我的回答是特定于 Linux 的。如果你想更跨平台,使用POSIX函数sigaction结合pause;这将为您提供更多控制权。

tokio 的文档非常棒getting started guide在东京的信号。因此,我将尝试添加我自己的建议。

我的一般建议是让一个任务为我们处理信号,然后您在其他任务中使用一个 watch channel ,如果 watch channel 状态发生变化,该 channel 将停止。

我的第二个建议是将 biased 与等待您的 future 的 select 一起使用,这很重要,因为您通常想知道是否立即收到信号并且之前没有做其他事情。这可能是一个经常准备好的繁忙循环的问题,你永远不会得到你的信号 future 分支。请仔细阅读 documentation关于有偏见

use core::time::Duration;

use tokio::{
select,
signal::unix::{signal, SignalKind},
sync::watch,
time::sleep,
};

#[tokio::main]
async fn main() {
let (stop_tx, mut stop_rx) = watch::channel(());

tokio::spawn(async move {
let mut sigterm = signal(SignalKind::terminate()).unwrap();
let mut sigint = signal(SignalKind::interrupt()).unwrap();
loop {
select! {
_ = sigterm.recv() => println!("Recieve SIGTERM"),
_ = sigint.recv() => println!("Recieve SIGTERM"),
};
stop_tx.send(()).unwrap();
}
});

loop {
select! {
biased;

_ = stop_rx.changed() => break,
i = some_operation(42) => {
println!("Result is {i}");
unsafe { libc::raise(libc::SIGTERM)};
},
}
}
}

async fn some_operation(i: u64) -> u64 {
println!("Task started.");
sleep(Duration::from_millis(i)).await;
println!("Task shutting down.");
i
}

您可以根据需要克隆 channel 的接收器,这将提高处理信号的效率。


东京0.1

实现您想要的一种方法是使用 tokio_signal crate 来捕捉信号,像这样:(doc example)

extern crate futures;
extern crate tokio;
extern crate tokio_signal;

use futures::prelude::*;
use futures::Stream;
use std::time::{Duration, Instant};
use tokio_signal::unix::{Signal, SIGINT, SIGTERM};

fn main() -> Result<(), Box<::std::error::Error>> {
let mut runtime = tokio::runtime::Runtime::new()?;

let sigint = Signal::new(SIGINT).flatten_stream();
let sigterm = Signal::new(SIGTERM).flatten_stream();

let stream = sigint.select(sigterm);

let deadline = tokio::timer::Delay::new(Instant::now() + Duration::from_secs(5))
.map(|()| println!("5 seconds are over"))
.map_err(|e| eprintln!("Failed to wait: {}", e));

runtime.spawn(deadline);

let (item, _rest) = runtime
.block_on_all(stream.into_future())
.map_err(|_| "failed to wait for signals")?;

let item = item.ok_or("received no signal")?;
if item == SIGINT {
println!("received SIGINT");
} else {
assert_eq!(item, SIGTERM);
println!("received SIGTERM");
}

Ok(())
}

该程序将等待所有当前任务完成并捕获选定的信号。这在 Windows 上似乎不起作用,因为它会立即关闭程序。

关于asynchronous - 如何优雅地关闭 Tokio 运行时以响应 SIGTERM?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53458755/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com