回调接进来,大多数文章讲到验签、去重、分发就完了。但我们踩过一个坑:事件按类型分发,同一业务实体的事件没串起来------一个客户的"加好友""发消息""打标签"三个事件分进三个处理器,谁也不知道对方处理到了哪一步,业务状态乱了。
问题的根源是事件分发按"类型"分,而业务状态按"实体"管。同一客户的事件必须串在同一条处理链上,才能保证状态一致。这篇讲怎么把事件驱动和业务状态机结合起来。
接口层用的是 Eyun 平台 开放的企微 API,凭证在Eyun 平台首页开通,回调走 Webhook。
接收层:只做投递
回调进来先验签、去重,然后按"业务实体 ID"而不是事件类型投递到同一个队列。客户相关事件(加好友、发消息、标签变更)投递到 conversation_id 对应的队列,同一会话的事件串行处理,天然保证顺序。
状态机:实体当前在哪一步
给每个业务实体(客户、工单、群)建一个状态机。以客户为例:
[新客] → 沟通中 → 已报价 → 已成交
↓
沉默(30天没互动)
每个状态定义允许的事件、触发的动作、转移后的新状态。事件进来先查实体当前在哪个状态,再判断这个状态接不接受这个事件,接受就执行动作并转移状态。
事件处理器:无副作用的状态转移
处理器本身不做业务副作用(不发消息、不改业务库),只做状态转移计算:输入是当前状态和事件,输出是新状态和要执行的副作用列表。副作用由状态机引擎统一执行------发欢迎语、建工单这些动作从副作用列表里取出来执行。
这样做的好处是事件进来先算状态对不对,不对直接丢弃,不会在错误状态下触发副作用。
事件乱序怎么办
回调可能乱序:客户先发了消息,再加了好友。状态机能处理:"发消息"事件进来时客户还在"未关联"状态,这个状态不接受发消息事件,处理器返回忽略。等到"加好友"事件来了,状态转"新客",再补处理被忽略的消息事件。
幂等与回放
状态转移本身要幂等:同一事件处理两次,结果一样。实体状态持久化在数据库,服务重启后从断点继续,不丢事件不重放错状态。
事件驱动的核心不是"事件来了调个函数",而是"事件来了让业务实体往前走一步"。状态机串起同一实体的事件,副作用统一执行,状态持久化保证不丢不乱------这三点做对了,回调处理才是业务驱动的,而不是事件驱动的。