Event.Subscribe - dotnet-shashlik/shashlik.eventbus GitHub Wiki
事件订阅使用接口 IEventHandler<TEvent>,泛型参数即为订阅的事件类型。事件处理类将自动注册到 DI 容器,无需手动注册。处理器不关心事件是否为延迟事件,延迟由发布方决定。
public interface IEventHandler<in TEvent> where TEvent : IEvent
{
Task Execute(TEvent @event, IDictionary<string, string> items);
}参数说明:
-
TEvent @event:事件实例 -
IDictionary<string, string> items:附加数据,EventBus 已自动添加以下 key:-
eventbus-msg-id:消息 ID -
eventbus-send-at:发送时间 -
eventbus-delay-at:延迟执行时间 -
eventbus-event-name:事件名称
-
// 一个事件可以有多个处理类,可以分布在不同的微服务中
// 但类名不可重复,默认类名会定义为消息队列中的 queue/group
// 发送短信的处理类
public class NewUserEventForSmsHandler : IEventHandler<NewUserEvent>
{
public async Task Execute(NewUserEvent @event, IDictionary<string, string> items)
{
// 发送短信...
}
}
// 发放消费券的处理类
public class NewUserEventForCouponsHandler : IEventHandler<NewUserEvent>
{
public async Task Execute(NewUserEvent @event, IDictionary<string, string> items)
{
// 业务处理...
}
}
// 延迟活动推送的处理类
public class NewUserPromotionEventHandler : IEventHandler<NewUserPromotionEvent>
{
public async Task Execute(NewUserPromotionEvent @event, IDictionary<string, string> items)
{
// 业务处理...
}
}事件处理器名称默认规则为 {Type.Name}.{Environment},对应消息队列中的 queue/groupId。可通过 [EventBusName] 特性显式声明:
[EventBusName("order.send-sms")]
public class OrderCreatedSmsHandler : IEventHandler<OrderCreatedEvent>
{
// ...
}以 RabbitMQ + Production 环境为例:
-
[EventBusName("order.send-sms")]→ 绑定到队列order.send-sms.Production - 无特性 → 绑定到队列
OrderCreatedSmsHandler.Production
处理器通过 EventBusOptions.HandlerServiceLifetime 配置注册到 DI 容器的生命周期,默认为 Transient。每个处理器在独立的 IServiceScope 中创建实例,支持 scoped 依赖注入。
EventBus 不能保证消息的幂等性。 为了保证消息的可靠传输,EventBus 及消息中间件对消息 QOS 处理等级必须为 at least once(至少到达一次),一般消息中间件都需要开启消息持久化避免消息丢失。
一个事件处理类可能处理多次同一个事件,消息的幂等性必须由业务方处理。例如:
- 用户订单付款完成后修改订单状态为待发货,可能在处理器中收到多次同一订单的付款完成事件
- 幂等处理:在处理器中使用锁或判断订单状态,如果订单状态已经为待发货,则直接返回并忽略本次事件