异步通信微服务:操作成功完成后如何通知终端用户
异步MQ任务完成后的应用内实时通知实现方案
核心逻辑是给每个异步任务做唯一标识做路由,在服务端和客户端之间建立可定向投递的实时通道,整套方案可以覆盖所有异步操作场景,不需要针对单个业务做定制开发。
方案1:WebSocket双向长连接(主选方案,实时性最优)
这是最接近同步请求体验的方案,毫秒级延迟,适配所有场景:
- 任务打标:客户端发起请求后,后端先生成全局唯一的
task_id,把携带task_id、发起用户ID、业务参数的消息投递给MQ,立刻把task_id随接口响应返回给客户端,客户端本地暂存task_id,将对应操作标记为「处理中」状态。 - 连接绑定:客户端完成身份认证后,和后端推送服务建立WebSocket长连接,服务端把当前连接和用户ID做映射,存在本地连接池里。如果是集群部署,节点间通过Redis Pub/Sub做事件广播即可,不需要额外的复杂路由。
- 结果投递:MQ消费者完成任务处理后,不直接操作客户端连接,而是把包含
task_id、处理状态(成功/失败)、业务返回数据、错误提示的任务完成事件,发送给推送服务集群。持有对应用户长连接的节点收到事件后,直接把消息推送给客户端。 - 客户端响应:客户端收到推送后,匹配本地暂存的
task_id,找到对应的等待操作,直接弹出结果提示、更新页面状态即可,比如更新资料场景下就把「保存中」的按钮状态改为正常,提示「资料更新成功」,同步刷新本地缓存的用户信息。
- 注意事项:要实现连接心跳保活、客户端断线重连逻辑;客户端重连成功后,主动拉取一次当前账号下所有未完成的任务状态,避免网络波动导致消息遗漏。
方案2:SSE服务端推送(轻量场景备选)
如果你的场景只需要服务端单向给客户端推消息,不需要客户端通过长连接传自定义数据,可以选SSE,实现成本比WebSocket低:
- 基于原生HTTP协议,不需要做协议升级,前端直接用原生
EventSourceAPI即可接入,自带断线重连能力。 - 整体流程和WebSocket一致:返回
task_id-> 客户端建立SSE连接绑定身份 -> MQ消费完成后推送事件到SSE服务 -> 服务端顺着HTTP长连接把结果推给客户端。
- 局限性:属于单向通信,浏览器对同域下的SSE连接数有默认限制,不适合高交互的复杂应用。
方案3:短轮询(兜底方案)
单独实现一个任务状态查询接口GET /api/task/status?task_id=xxx,当客户端长连接建立失败、或者处于弱网极端场景时,可以每隔1~2秒轮询一次该接口,查询到任务完成结果就停止轮询。
- 不建议作为主方案使用,轮询会给服务端带来额外的请求压力,实时性也弱于长连接方案,只用来做兼容兜底。
通用适配层设计(全场景覆盖的关键)
不要给每个业务场景单独写通知逻辑,抽一层公共的异步任务中心做统一处理:
- 所有投递到MQ的异步任务,都由任务中心统一生成
task_id,持久化存储任务元数据:操作类型、发起用户ID、任务参数、创建时间、处理状态、返回结果。 - MQ侧所有业务消费者处理完任务后,统一调用任务中心的回调接口更新任务状态,触发通知事件。后续不管是应用内长连接推送、还是要扩展其他通知渠道,都在这一层做统一路由分发,业务代码完全不需要感知通知逻辑。
- 客户端也抽一层统一的异步任务监听层,所有接口返回的
task_id都交给监听层托管,不管是长连接推送的结果还是轮询拿到的结果,匹配到task_id后自动分发给对应的业务页面,不需要每个页面单独实现通知接收逻辑。
避坑提醒:不要在MQ消费服务里直接持有WebSocket连接引用推送消息,一旦服务做了多实例集群部署,消费端根本拿不到用户所在的连接实例,100%会出现消息投递失败的问题。
内容的提问来源于stack exchange,提问作者Akshay Champavat
相关产品推荐
相关产品推荐

