biedongbin opened a new issue, #7840: URL: https://github.com/apache/incubator-seata/issues/7840
### Check Ahead - [x] I have searched the [issues](https://github.com/seata/seata/issues) of this repository and believe that this is not a duplicate. - [ ] I am willing to try to implement this feature myself. ### Why you need it? 解决空补偿和悬挂问题。 项目背景: seata 最新版本2.5.0 ,saga 注解模式, 集成nacos 作为注册中心和配置中心, 微服务集群 也使用了nacos 作为注册中心。 翻遍了官方文档以及 QA 和issue 和调试了源码 未能有解决次问题的处理。研究发现以下情况: 1. 核心代码:org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler#proceed 此处主要处理 分支注册、doBeforeTccPrepare hook 执行, 执行业务代码,finally 执行 doAfterTccPrepare hook代码, 以及 分支上报(固定了 BranchStatus.Registered 状态) 2. 上游全局事务异常回滚时,会对所有 BranchStatus.Registered 状态的子分支 进行补偿调用, 此时存在问题 即使本次业务执行 异常了 那么其补偿方法也依旧会被执行 3. 如果此方法执行时间长 假设30秒,上游超时时间是5秒,那么上游调用5秒之后 异常回滚, 此方法的补偿方法也会被调用,并且在 此方法执行30秒之后 上报分支事务时 异常 不会再次补偿 ### How it could be? 正向业务代码的执行结果有几种情况 1 执行成功 2 执行异常 3 执行超时-异常 4 执行超时-成功 上述4种情况, 在补偿方法的业务逻辑内是无法感知的,所以 应对空补偿和悬挂 处理就比较麻烦,对业务的考验比较强。 建议逻辑: 1 引入一个 业务状态字段 2 hook 添加 onException 3 补偿方法的调度 进行状态判断, 仅限执行成功或者执行异常的情况 才发起实际调用 (即 必须确保补偿方法的调用一定是在正向方法执行结束之后执行,确保事务的最终一致性) === 针对当前现状 ,我这边的项目使用 进行了2次包装,设计思路如下: #### 1. 公共 Saga 服务层 **设计理念**:提供统一的 `SagaTransactionService`,使用 Seata 原生注解 `@CompensationBusinessAction` 作为事务入口,同时封装补偿方法调用逻辑。 #### 2. Callback 函数参数录入 **设计理念**:SagaTransactionService 的正向接口接收业务方法的 Callback 函数作为实际执行处理器,实现业务逻辑与事务框架的解耦。 **实现要点**: - 使用 `ThrowingSupplier<T>` 函数式接口封装业务逻辑 - 支持业务方法返回任意类型的结果 - 通过 AOP 切面自动将业务方法转换为 Callback 函数 #### 3. 事务状态上报机制 **设计理念**:业务方法执行完毕后,通过 `BusinessActionContext` 写入 `status = "end"` 状态,标记事务分支执行成功。 **实现要点**: - 在 `SagaTransactionService.execute()` 方法末尾设置状态 - 使用 `BusinessActionContextUtil.getContext().addActionContext("status", "end")` - 确保只有业务逻辑完全执行成功才设置完成状态 #### 4. Saga 状态钩子监控 **设计理念**:新增 `SagaStatusHook` 实现 Seata 的 `TccHook` 接口,在 `afterTccPrepare` 阶段检查事务状态,对异常情况进行干预。 **实现要点**: - 实现 `TccHook.afterTccPrepare` 方法 - 检查 `BusinessActionContext` 中的 `status` 字段 - 若状态不是 `"end"`,则标记为 `"error"` 强制上报异常 #### 5. 补偿方法状态判断 **设计理念**:补偿方法首先获取并判断事务状态,根据不同状态执行相应的补偿策略,实现智能的补偿决策。 **状态判断逻辑**: - **`status == null`**:正向方法未执行完毕,返回 `false` 触发 TC 重试 - **`status == "error"`**:正向方法执行失败,返回 `true` 无需补偿 - **`status == "end"`**:正向方法执行成功,执行具体的补偿业务逻辑 **实现要点**: - 在 `compensate()` 方法开始处进行状态检查 - 根据状态值返回相应的布尔值控制补偿行为 - 详细记录状态判断的日志信息 #### 6. 自定义注解与 AOP 拦截 **设计理念**:通过自定义注解 `@CustomCompensationBusinessAction` 标记业务方法,使用 AOP 切面拦截注解方法,在切面内部调用 SagaTransactionService 的正向方法,并传递补偿处理器类信息 以便写入事务上下文在补偿方法执行时获取 并发起实际调用。 === 最终子业务使用的时候 类似这样 `public class StockLockService extends AbstractCompensationHandler { /** * 锁定库存 */ @CustomCompensationBusinessAction(handler = RemoteStockLockService.class) public void lockStock(@BusinessActionContextParameter IvStockLockForm lockForm) { } @Override public boolean compensate(BusinessActionContext businessActionContext) { return true; } }` ==== 综上, 请分析下 上述设计是否合理, 社区是否愿意引入 此类设计,我愿意花时间 按社区的标准贡献合规的代码 ### Other related information [CustomSagaAspect.java](https://github.com/user-attachments/files/24067741/CustomSagaAspect.java) [CustomSeataAutoConfiguration.java](https://github.com/user-attachments/files/24067738/CustomSeataAutoConfiguration.java) [FeignConfig.java](https://github.com/user-attachments/files/24067742/FeignConfig.java) [SagaStatusHook.java](https://github.com/user-attachments/files/24067739/SagaStatusHook.java) [SeataHttpRequestInterceptor.java](https://github.com/user-attachments/files/24067740/SeataHttpRequestInterceptor.java) [AbstractCompensationHandler.java](https://github.com/user-attachments/files/24067746/AbstractCompensationHandler.java) [CustomCompensationBusinessAction.java](https://github.com/user-attachments/files/24067745/CustomCompensationBusinessAction.java) [SagaTransactionService.java](https://github.com/user-attachments/files/24067747/SagaTransactionService.java) [ThrowingSupplier.java](https://github.com/user-attachments/files/24067748/ThrowingSupplier.java) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
