跨进程事件通知
跨进程事件通知 不同于简单的HTTP调用通知:它是一种一对多的通知方式。
典型场景:
- 数据修改后通知【多个进程】及时刷新内存中缓存
发布事件通知
AppEvent.PublishGlobalEvent("insert.userservice.userrole", "usercode");
AppEvent.PublishGlobalEvent("update.userservice.userrole", "123", "usercode");
PublishGlobalEvent方法签名
/// <summary>
/// 发送【跨进程】事件,事件以异步方式交给EventHandler执行。
/// </summary>
/// <param name="name">事件名称</param>
/// <param name="param1">参数1</param>
/// <param name="param2">参数2</param>
/// <param name="param3">参数3</param>
public static void PublishGlobalEvent(string name, string param1 = null, string param2 = null, string param3 = null)
为什么是3个参数(param1/param2/param3)?
设计原因:
- 使用简单:大多数简单场景可以直接使用简单数据类型(int/string)
- 例如:缓存更新时,可以只指定 param1=cacheKey 参数即可
- 方便过滤:减少反序列次数
- 由于通知会发送给集群内所有进程,为了便于过滤,可以将过滤条件赋值给 param2/param3
说明:
- 以上只是使用建议,你可以给param1/param2/param3赋值任意复杂的JSON文本,甚至是null
- 这3个参数具体表达什么含意,由每个事件来决定!
订阅&处理事件
public class XxxEventHandler : BaseAppEventHandler
{
[EventAction(EventName = "insert.userservice.userrole")]
public void Method1(AppEventArgs e)
{
// 事件处理逻辑
}
[EventAction(EventName = "update.userservice.userrole")]
public async Task Method2(AppEventArgs e)
{
// 事件处理逻辑
}
}
注意事项:
- 事件订阅类型必须定义成 public ,且必须从 BaseAppEventHandler 继承
- 订阅事件的方法必须定义成 public
- 方法的返回值类型只能是 void 或者是 Task
- 方法只能包含一个参数,类型是 AppEventArgs
- 方法必须用 [EventAction] 来明确指定要订阅的事件名称
如何忽略某个事件?
方法:
- 不订阅那个事件
说明:
- 事件处理方法是异步调用的,不会阻塞发布方,也没有返回值
- 不论事件如何处理,对发布方是没有影响的
与消息处理相比
【跨进程事件通知】与【消息处理】其实是非常类似的设计。
跨进程事件通知 的主要设计目标是:
- 轻量化
- 易用使用
具体的技术差异在于:
技术特性 | 跨进程事件通知 | MQ消息处理 |
---|---|---|
创建队列 | 不需要 | 需要事先创建或者程序初始化时创建 |
主动订阅 | 不需要 | 需要程序初始化时主动订阅某个队列 |
作用范围 | 所有进程 | 由开发人员决定 |
消息持久化 | 不支持 | 由队列服务决定(绝大部分支持) |
订阅者数量 | 固定=1 | 支持多个,可配置 |
异常处理 | 非常简陋 | 默认支持,且允许重写(自定义) |
重试处理 | 不支持 | 支持,且允许重写重试过滤条件 |
日志 | 没有 | 有 |
监控 | 没有 | 有 |
注意事项
基于上表描述,跨进程事件通知只能用于【比较简单】的通知场景,且在使用时应该注意:
- 事件会发送所集群内的所有进程,所以请优先考虑使用MQ的方式解决
- 事件处理方法必须要快速完成,否则当出现大量事件时,会导致事件丢失
- 默认的异常处理仅仅是 Console.Write,如果需要记录到异常日志,请手动处理