跨进程事件通知

跨进程事件通知 不同于简单的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,如果需要记录到异常日志,请手动处理