如何在 Rust 中启动多个服务器/进程,并在 SIGINT/SIGTERM 上关闭它们?



这是我使用 Rust 的第三天。我正在其中开发一个网络服务。这是我尝试实现的模式:

主要应用程序结构:

/// Application is the main application struct.
struct Application {
/// adapters is the list of various servers/processes that constitute the Application.
adapters: Vec<Box<dyn IAdapter>>,
}
/// Application is the main application implementation.
impl Application {
/// start method launches the Application by starting all the adapters.
async fn start(&self) {}
/// stop method stops the Application by stopping all the adapters.
async fn stop(&self) {}
}

这是适配器特征:

/// IAdapter represents an Application process.
pub trait IAdapter {
/// name provides the name of the Adapter.
fn name(&self) -> String;
/// start starts the adapter.
fn start(&self) -> PinFuture<OptionBoxErr>;
/// stop stops the adapter.
fn stop(&self) -> PinFuture<OptionBoxErr>;
}

以下是适配器特征中使用的类型别名:

/// PinFuture<T> is essentially Future<Output = T>
pub type PinFuture<T> = Pin<Box<dyn Future<Output = T>>>;
// OptionBoxErr is essentially Option<Error>
pub type OptionBoxErr = Option<Box<dyn Error>>;

在这里,IAdapter特征可以通过应用程序中可能想要的任何进程来实现,例如:HTTP 服务器或 cron 作业管理器。

以下是我知道我需要做的事情,但由于 Rust 的严格性而不能做。

  1. main方法调用Applicationstart方法,该方法又同时遍历所有adapters以调用其start方法。此流将启动整个应用程序。

  2. main方法在某些时候也会为 SIGINT/SIGTERM 设置一个侦听器,以调用Applicationstop方法,然后再次遍历所有adapters调用它们的stop方法。此流正常关闭整个应用程序。

以下是我到目前为止设法做到的丑陋:

fn main() {
let application = Application {
adapters: vec![
/* HTTP server */
/* Cron Job Manager */
],
};
let application_stop_future = async {
println!("Attaching signal listener.");
let mut signals = signal_hook::iterator::Signals::new(&[SIGINT]).unwrap();
signals.forever().next();
println!("Shutting down the Application...");
application.stop().await;
//  ^^^^^^^^^^^ Does not live long enough.
};
let application_start_future_boxed = Box::pin(application.start());
//                                            ^^^^^^^^^^^ Does not live long enough.
let application_stop_future_boxed = Box::pin(application_stop_future);
let futures_vec: Vec<PinFuture<()>> = vec![
application_start_future_boxed,
application_stop_future_boxed,
];
// block_on blocks until the provided Future is resolved.
futures::executor::block_on(future::select_all(futures_vec));
}

有点明白为什么它不起作用。但我完全不知道除此之外该怎么做。另外,我什至没有触及Application.start将同时调用IAdapter.start方法的部分。

指望一些帮助。顺便说一句,如果你想使用它的类比,我精通围棋。

尽量不要太注意我创建的类型别名。我只是在与编译器作斗争以使事情正常工作。

尚未检查代码以确保这有效,但是将适配器字段类型更改为Arc<Vec<Box<dyn IAdapter>>>并为结构派生克隆应该允许您在将应用程序对象插入application_stop_future时仅克隆应用程序对象,从而避免"对象移动"问题

您的系统架构看起来很接近"参与者模型"。 我会看看 https://crates.io/crates/actix-web

最新更新