StackSaga 事务类型全景详解

本章将为您全景拆解 StackSaga 框架的底层协调架构。 除此之外,您还将深入理解在微服务架构落地过程中不可避免要面对的技术限制,以及如何通过 StackSaga 框架以标准化、低心智负担的方式逐一攻克这些难点。

在 Saga 业务流转中,依据事务在运行时的不同行为与最终落地点,可将事务归纳为 3 大典型类别。 下面让我们逐一剖析 StackSaga 的执行协调器 (Saga Execution Coordinator, SEC) 是如何在每种事务类型下协同调度各组件的:

完全成功事务场景 (Fully Success Transaction)

在此场景中,Saga 执行协调器 (SEC) 成功推进并执行了链路中的所有执行器 (Executors)。因此,全程未触发任何逆向补偿回滚操作。这是所有业务交易最理想的成功黄金路径。

StackSaga 高层级执行架构图
  • 1 用户发起请求:客户端发起下单请求,由 Spring MVC 的 OrderController 接收请求入口。

  • 2 初始化领域实体与启动执行器:控制器接收到请求后,初始化下单领域的 DomainEntity 实例,并将起始执行器 (CreateOrderExecutor) 配置给 StackSaga 引擎。 (在此阶段,框架已自动为该请求生成了全局唯一的 transaction uid。该唯一标识符代表该事务实例的生命周期,可直接从您创建的 DomainEntity 对象中获取。)

  • 3 SEC 协调接管:事务进入由 SEC 完全托管的状态机调度。 在调用您指定的起始执行器之前,SEC 会首先将 DomainEntity 的初始状态快照原子保存至事件存储 (Event Store) 中。

  • 4 执行起始执行器 ([Command] CreateOrderExecutor):

    • 4.1 SEC 调度执行器的 doProcess 方法,进而调用本地订单服务 InternalOrderService 的 createOrder() 方法。

    • 4.2 该本地方法成功返回后,SEC 将领域实体的最新状态快照更新持久化到事件存储中。

    • 4.3 状态快照保存完成后,SEC 自动回调您在 Handler 处理器中实现的 onEachProcessPerformed 钩子方法。

    • 4.4 您可以在该回调中执行自定义业务逻辑以更新订单状态。在示意图中,我们调用了 InternalOrderService 的 updateCustomerOrderStatus() 方法。

    • 4.5 更新状态后,系统可通过发送邮件或短信通知客户订单已成功创建。

  • 5 执行第 2 个执行器 ([Query] UserExecutor):起始执行器成功后,指定导航至第 2 个执行器。

    • 5.1 SEC 触发只读查询执行器 [Query] UserExecutor 的 doProcess 方法,调用 ExternalUserStatusService 的 checkUser() 方法。

    • 5.2 ExternalUserStatusService 向下游的 user-service(用户微服务)发起远程调用以验证用户信息。

    • 5.3 远程调用成功返回后,SEC 保存第 2 个步骤的领域实体快照。

    • 5.4 SEC 回调 Handler 类的 onEachProcessPerformed 方法。

      注:由于该执行器属于纯只读的 QueryExecutor,因此在此处无需执行任何状态变更或订单数据更新。

  • 6 执行支付执行器 ([Command] PaymentExecutor):

    • 6.1 SEC 调用 [Command] PaymentExecutor 的 doProcess 方法,触发 ExternalPaymentService 的 makePayment() 方法。

    • 6.2 ExternalPaymentService 向外部的 payment-service(支付微服务)发起远程扣款请求。

    • 6.3 扣款调用成功后,SEC 持久化领域实体的更新状态。

    • 6.4 SEC 回调 Handler 的 onEachProcessPerformed 方法。

    • 6.5 在回调中调用 updateCustomerOrderStatus() 将订单状态变更为“已支付”。

    • 6.6 向客户推送支付成功的通知消息。

  • 7 执行发货执行器 ([Command] DeliveryExecutor):

    • 7.1 SEC 调用 [Command] DeliveryExecutor 的 doProcess 方法,触发 ExternalDeliveryService 的 addToDelivery() 方法。

    • 7.2 ExternalDeliveryService 远程调用 delivery-service(物流派送服务),请求将包裹加入派送队列。

    • 7.3 调用成功后,SEC 记录状态快照。

    • 7.4 SEC 回调 Handler 的 onEachProcessPerformed 方法。

    • 7.5 更新订单流转状态为“配送中”。

    • 7.6 发送短信或 App 推送通知客户订单已出库。

  • 8 事务成功终结:作为全流程的最终里程碑,SEC 回调 Handler 的 onTransactionCompleted 方法。

    • 8.1 将订单最终状态标记为全局已完成(SUCCESS)。

    • 8.2 向客户下发最终交易成功凭证。

补偿成功事务场景 (Compensating Success Transaction)

在此场景中,SEC 未能全部执行完所有正向执行器。在执行途中某个步骤发生了业务异常或不可恢复错误。因此,Saga 引擎立即启动逆向补偿流程,将此前成功执行的步骤逐一逆向撤销。

StackSaga 补偿成功事务场景架构图
  • 1 用户发起请求:客户端发起下单请求,由 Spring MVC 的 OrderController 接收请求入口。

  • 2 初始化领域实体:初始化下单领域的 DomainEntity,配置起始执行器并将事务委托给 StackSaga。 (在此阶段,框架自动分配全局唯一的 transaction uid,可直接通过 DomainEntity 对象获取。)

  • 3 SEC 协调接管:在正式调用起始执行器前,SEC 将 DomainEntity 的初始状态快照原子写入事件存储 (Event Store)。

  • 4 执行起始执行器 ([Command] CreateOrderExecutor):

    • 4.1 SEC 触发 doProcess,调用 InternalOrderService 的 createOrder() 方法在本地创建订单。

    • 4.2 调用成功后,SEC 将领域实体的最新状态快照保存至事件存储。

    • 4.3 快照落盘后,SEC 回调 Handler 的 onEachProcessPerformed 方法。

    • 4.4 业务层在回调中更新订单状态为“已创建”。

    • 4.5 异步下发短信或邮件通知客户订单已成功受理。

  • 5 执行第 2 个执行器 ([Query] UserExecutor):

    • 5.1 SEC 调度 [Query] UserExecutor 的 doProcess 方法,调用 ExternalUserStatusService 的 checkUser()。

    • 5.2 ExternalUserStatusService 远程调用 user-service 验证用户信息。

    • 5.3 调用成功返回后,SEC 记录状态快照。

    • 5.4 SEC 回调 Handler 的 onEachProcessPerformed 方法。

      注:由于该执行器属于纯查询性质的 QueryExecutor,因此在此处不涉及任何状态变更或订单数据更新。

  • 6 执行支付执行器时发生异常 ([Command] PaymentExecutor):

    • 6.1 SEC 调度 PaymentExecutor 的 doProcess 方法,触发 ExternalPaymentService 的 makePayment()。

    • 6.2 ExternalPaymentService 远程向 payment-service 发起扣款请求。在此步骤中,调用发生异常(例如用户信用卡额度不足或账户已被冻结)。

  • 7 异常捕获与补偿启动:

    • SEC 捕获到执行异常,并立即回调 Handler 的 onProcessException 钩子方法,通知业务层*处理过程发生失败*。

    • 由于该异常不可继续正向重试推进,正向执行流在此终止,Saga 引擎立即从此节点切换为逆向补偿流程 (Compensating Process)。

      (注:如果需要在此刻向用户下发退单提示或预先更新订单状态,可在该回调中执行相应代码。)

  • 8 逆向执行补偿逻辑:

    • 倒序查找需要被撤销的步骤。由于 UserExecutor 是纯查询操作,无需任何补偿;因此补偿流程直接定位至上一个 CommandExecutor —— 即 OrderExecutor。

    • SEC 调度 OrderExecutor 的 doRevert 补偿方法。

    • 8.1 doRevert 方法内部调用 createOrderRevert,将此前创建的订单记录状态置为“已取消/已作废”。

    • 8.2 如果在补偿过程中需要暂存特定回滚元数据(如撤销凭据、日志或批注),可将其保存至框架提供的回滚提示存储 (Revert-Hint-Store) 中。

    • 8.3 补偿逻辑顺利执行完毕后,SEC 自动回调 Handler 的 onEachRevertPerformed 钩子方法。

    • 8.4 业务系统通知客户由于扣款失败,订单已自动撤销。

  • 9 补偿完成终态确认:

    • StackSaga 状态机确认所有已提交的步骤均已完全反向补偿完毕。

    • SEC 调用 Handler 的 onTransactionCompleted 回调,传入终态标识 REVERT_SUCCESS(补偿成功)。

    • 9.1 业务层将订单记录更新为“已成功回滚 (REVERTED)”。

    • 9.2 向用户推送订单已全额撤销的终态确认凭证。

为了保障分布式长事务在全局视角下的最终一致性,补偿过程本身也是支持自动重试的。因为无论发生什么网络抖动,所有必须执行的补偿动作都必须确保被彻底调用。欲深入了解 StackSaga 中逆向补偿的重试工作机制,请参阅相关异常与重试说明文档。

补偿失败事务场景 (Compensating Failed Transaction)

StackSaga 补偿失败事务场景架构图
尽管*补偿失败事务*在理论分布式系统中属于小概率的边缘边界情况,但在生产级企业应用中,研发团队必须通过防御性编程确保逆向补偿逻辑绝不抛出未经处理的不可逆异常。
我们能否在某个补偿步骤抛出异常时忽略该错误,继续强制执行其余步骤的补偿?
答案是肯定的。 在默认情况下,如果在逆向补偿全链路中某个步骤抛出了未捕获的严重异常,整个事务的状态推进将停滞在该故障点。 这意味着排在该步骤前面的其他待补偿步骤将被暂时阻塞,无法继续向下执行。
在很多关键业务中,排在更前面的补偿步骤(例如退款或解锁库存)至关重要且必须执行。如果中途某个次要补偿步骤报错导致核心补偿无法执行,将会引发严重的业务账目不一致。
大多数情况下,此类意外异常往往是代码未能妥善防御的边缘情况。
[ 欲查看防止事务因单点补偿异常而意外中断的实际代码示范,请参阅 快速入门示例 ]

StackSaga 事务类型全景摘要 (Summary Of StackSaga Transaction Types)

完全成功事务 (Fully Success Transaction)

完全成功事务架构全景摘要图

补偿成功事务 (Rollback/Compensating/Revert Success Transaction)

补偿成功事务架构全景摘要图

补偿失败事务 (Rollback/Compensating/Revert Failed Transaction)

补偿失败事务架构全景摘要图