90个版本 (17个破坏性更新)
新版本 0.18.4 | 2024年8月21日 |
---|---|
0.17.3 | 2024年8月13日 |
0.13.0 | 2024年7月31日 |
0.3.15 | 2024年3月21日 |
0.2.17 | 2023年11月19日 |
#605 in 异步
每月1,631次下载
70KB
1K SLoC
一个用于编写可靠和可扩展系统的基于事件的框架。
在较高层次上,它提供了一些主要组件
鲁瓦之旅
鲁瓦由多个模块组成,这些模块提供了一组对于在Rust中实现类似消息总线应用程序的必需功能。在本节中,我们将简要浏览,总结主要API及其用途。
TCommand & Event
您可以使用如下into_command派生宏将任何通用结构注册为以下内容
#[ruva::into_command]
pub struct MakeOrder {
pub user_id: i64,
pub items: Vec<String>,
}
当您附加into_command派生宏时,MessageBus现在将能够理解它应该如何以及在哪里调度命令。
同样,您可以对事件执行相同的操作
#[derive(Serialize, Deserialize, Clone, TEvent)]
#[internally_notifiable]
pub struct OrderFailed {
pub user_id: i64,
}
#[derive(Serialize, Deserialize, Clone, TEvent)]
#[externally_notifiable(OrderAggregate)]
pub struct OrderSucceeded{
#[identifier]
pub id: i64,
pub user_id: i64,
pub items: Vec<String>
}
请注意,internally_notifiable
事件不需要聚合规范,而externally_notifiable
事件则需要,包括其id和identifier
属性。
internally_notifiable
是标记,让系统知道该事件应在应用程序内部处理externally_notifiable
事件作为OutBox
存储。
初始化TCommandService
为了使消息总线能够识别服务处理器,必须实现TCommandService,其响应将直接发送给客户端。
pub struct MessageBus {
event_handler: &'static TEventHandler<ApplicationResponse, ApplicationError>,
}
impl ruva::TMessageBus<ApplicationResponse,ApplicationError, Command> for MessageBus{
fn command_handler(
&self,
context_manager: ruva::AtomicContextManager,
cmd: Command,
) -> impl ruva::TCommandService<ApplicationResponse, ApplicationError> {
HighestLevelOfAspectThatImplementTCommandService::new(
MidLevelAspectThatImplementTCommandService::new(
TargetServiceThatImplementTCommandService::new(
cmd, other_dependency
)
)
)
}
}
为了方便起见,鲁瓦提供了声明性宏,可以处理事务单元工作,您可以使用如下方式使用它
ruva::register_uow_services!(
MessageBus,
ServiceResponse,
ServiceError,
//Command => handler mapping
CreateUserAccount => create_user_account,
UpdatePassword => update_password,
MakeOrder => make_order,
DeliverProduct => deliver_product
)
注册事件
Event
是命令处理或另一个事件处理的副作用。只要所有处理程序都消耗相同类型的Event
,就可以注册尽可能多的处理程序,如下所示
示例
use ruva::ruva_core::init_event_handler;
init_event_handler!(
{
Response,
Error,
|ctx| YourServiceEventHandler::new(ctx),
OrderFaild: [
NotificationHandler::send_mail,
],
#[asynchronous]
OrderSucceeded: [
DeliveryHandler::checkout_delivery_items,
InventoryHandler::change_inventory_count
]
}
);
在MakeOrder
TCommand处理中,我们会有OrderFailed
或OrderSucceeded
事件,每个事件都有自己的处理程序。事件在处理程序中被触发,并由MessageBus抛出,由ContextManager触发。除非收到StopSentinel
,否则MessageBus会循环处理所有处理程序。
处理程序API示例(文档所需)
MessageBus
核心是事件驱动的库是MessageBus,它从UnitOfWork
获取命令和触发事件,并将事件分发给正确的处理程序。由于这仅在框架侧完成,因此您只有在调用它时才能“感觉到”messagebus的存在。其他所有事情都是神奇地完成的。
示例
#[ruva::into_command]
pub struct MakeOrder { // Test TCommand
pub user_id: i64,
pub items: Vec<String>
}
async fn test_func(){
let bus = MessageBus::new(command_handler(), event_handler())
let command = MakeOrder{user_id:1, items:vec!["shirts","jeans"]}
match bus.execute_and_wait(command,Box::new(connection_pool())).await{
Err(err)=> { // test for error case }
Ok(val)=> { // test for happy case }
}
}
}
}
MessageBus的错误
当命令尚未注册时,它返回一个错误 - BaseError::NotFound
请注意,与分布式事件处理不同,bus不返回事件处理的返回结果。
依赖关系
~8-25MB
~370K SLoC