这是我使用 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 的严格性而不能做。
main
方法调用Application
的start
方法,该方法又同时遍历所有adapters
以调用其start
方法。此流将启动整个应用程序。main
方法在某些时候也会为 SIGINT/SIGTERM 设置一个侦听器,以调用Application
的stop
方法,然后再次遍历所有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