Skip to content

TCC模式下,开启它的useTCCFence功能,在rollback方法中抛出一个异常,业务系统服务捕获到的异常信息为null #6665

@iAmClever

Description

@iAmClever

Ⅰ. Issue Description
TCC模式下,开启它的useTCCFence功能,在rollback方法中抛出一个异常,业务系统服务捕获到的异常信息为null

Ⅱ. Describe what happened
TCC模式下,开启useTCCFence功能,在触发rollback的时候,会调到【io.seata.rm.tcc.TCCFenceHandler#updateStatusAndInvokeTargetMethod】,这里会使用jdk的反射去调用业务系统的rollback方法,如果rollback方法出现异常,业务系统的异常信息会被吃掉,因为jdk反射method.invoke()方法为了对异常做统一处理,会把业务异常统一包装成InvocationTargetException类型。

业务系统服务错误栈如下:

2024-07-12 09:52:31.079 ERROR 22908 --- [_RMROLE_1_19_24] io.seata.rm.AbstractResourceManager      : rollback TCC resource error, resourceId: updateInventoryAcquire, xid: 10.244.137.109:8091:8944687993233431500.

java.lang.reflect.InvocationTargetException: null
	at jdk.internal.reflect.GeneratedMethodAccessor56.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.seata.rm.tcc.TCCFenceHandler.updateStatusAndInvokeTargetMethod(TCCFenceHandler.java:255)
	at io.seata.rm.tcc.TCCFenceHandler.lambda$rollbackFence$2(TCCFenceHandler.java:212)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
	at io.seata.rm.tcc.TCCFenceHandler.rollbackFence(TCCFenceHandler.java:187)
	at io.seata.rm.tcc.TCCResourceManager.branchRollback(TCCResourceManager.java:164)
	at io.seata.rm.AbstractRMHandler.doBranchRollback(AbstractRMHandler.java:125)
	at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:67)
	at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:63)
	at io.seata.core.exception.AbstractExceptionHandler.exceptionHandleTemplate(AbstractExceptionHandler.java:131)
	at io.seata.rm.AbstractRMHandler.handle(AbstractRMHandler.java:63)
	at io.seata.rm.DefaultRMHandler.handle(DefaultRMHandler.java:68)
	at io.seata.core.protocol.transaction.BranchRollbackRequest.handle(BranchRollbackRequest.java:35)
	at io.seata.rm.AbstractRMHandler.onRequest(AbstractRMHandler.java:150)
	at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.handleBranchRollback(RmBranchRollbackProcessor.java:63)
	at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.process(RmBranchRollbackProcessor.java:58)
	at io.seata.core.rpc.netty.AbstractNettyRemoting.lambda$processMessage$2(AbstractNettyRemoting.java:281)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.RuntimeException: 测试异常信息抛出
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl.rollback(UpdateInventoryAcquireActionImpl.java:105)
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl$$FastClassBySpringCGLIB$$147ec8e9.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at io.seata.spring.tcc.TccActionInterceptor.invoke(TccActionInterceptor.java:84)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl$$EnhancerBySpringCGLIB$$a9d3d742.rollback(<generated>)
	... 23 common frames omitted

2024-07-12 09:52:31.079  INFO 22908 --- [_RMROLE_1_19_24] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_RollbackFailed_Retryable
2024-07-12 09:52:31.108  INFO 22908 --- [           main] i.seata.tm.api.DefaultGlobalTransaction  : transaction end, xid = 10.244.137.109:8091:8944687993233431500
2024-07-12 09:52:31.108  INFO 22908 --- [           main] i.seata.tm.api.DefaultGlobalTransaction  : [10.244.137.109:8091:8944687993233431500] rollback status: RollbackRetrying
2024-07-12 09:52:31.109  WARN 22908 --- [           main] i.s.tm.api.DefaultFailureHandlerImpl     : Retrying to rollback transaction[10.244.137.109:8091:8944687993233431500]

Ⅲ. Describe what you expected to happen

在rollback方法中如果抛出异常信息后,业务系统可以获取到更加直观的异常信息

Ⅳ. How to reproduce it (as minimally and precisely as possible)

参考mybatis【org.apache.ibatis.reflection.ExceptionUtil#unwrapThrowable】对 反射调用方法抛出异常【InvocationTargetException】 or 对代理对象调用方法抛出异常【UndeclaredThrowableException】的处理,在捕获到异常类型是【InvocationTargetException】 、【UndeclaredThrowableException】,调用异常对象的【getTargetException】方法,以获取到被包装的原始异常对象,然后再抛出这个原始异常对象,这样业务系统就可以获取到更加直观的异常信息

优化后抛出的异常信息如下:

2024-07-12 10:08:58.305 ERROR 3976 --- [_RMROLE_1_24_24] io.seata.rm.AbstractResourceManager      : rollback TCC resource error, resourceId: updateInventoryAcquire, xid: 10.244.137.109:8091:8944687993233386807.

java.lang.Exception: java.lang.RuntimeException: 测试异常信息抛出
	at io.seata.rm.tcc.TCCFenceHandler.updateStatusAndInvokeTargetMethod(TCCFenceHandler.java:270)
	at io.seata.rm.tcc.TCCFenceHandler.lambda$rollbackFence$2(TCCFenceHandler.java:212)
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
	at io.seata.rm.tcc.TCCFenceHandler.rollbackFence(TCCFenceHandler.java:187)
	at io.seata.rm.tcc.TCCResourceManager.branchRollback(TCCResourceManager.java:164)
	at io.seata.rm.AbstractRMHandler.doBranchRollback(AbstractRMHandler.java:125)
	at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:67)
	at io.seata.rm.AbstractRMHandler$2.execute(AbstractRMHandler.java:63)
	at io.seata.core.exception.AbstractExceptionHandler.exceptionHandleTemplate(AbstractExceptionHandler.java:131)
	at io.seata.rm.AbstractRMHandler.handle(AbstractRMHandler.java:63)
	at io.seata.rm.DefaultRMHandler.handle(DefaultRMHandler.java:68)
	at io.seata.core.protocol.transaction.BranchRollbackRequest.handle(BranchRollbackRequest.java:35)
	at io.seata.rm.AbstractRMHandler.onRequest(AbstractRMHandler.java:150)
	at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.handleBranchRollback(RmBranchRollbackProcessor.java:63)
	at io.seata.core.rpc.processor.client.RmBranchRollbackProcessor.process(RmBranchRollbackProcessor.java:58)
	at io.seata.core.rpc.netty.AbstractNettyRemoting.lambda$processMessage$2(AbstractNettyRemoting.java:281)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.RuntimeException: 测试异常信息抛出
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl.rollback(UpdateInventoryAcquireActionImpl.java:105)
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl$$FastClassBySpringCGLIB$$147ec8e9.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at io.seata.spring.tcc.TccActionInterceptor.invoke(TccActionInterceptor.java:84)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
	at com.anycubic.cerp.inventory.service.inventory.action.UpdateInventoryAcquireActionImpl$$EnhancerBySpringCGLIB$$e4bf58ac.rollback(<generated>)
	at jdk.internal.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.seata.rm.tcc.TCCFenceHandler.updateStatusAndInvokeTargetMethod(TCCFenceHandler.java:256)
	... 19 common frames omitted

Ⅴ. Anything else we need to know?

我的想法是在seata-tcc模块里面新建一个ExceptionUtil类,并提供一个unwarp方法,在有反射方法调用的地方,需要捕获这个异常,并调用【ExceptionUtil】工具类做一层异常转换后再抛出这个异常。

如果认定这是一个 优化,我可以尝试提交修改的 PR ~~~

Ⅵ. Environment:

JDK version(e.g. java -version): 11
Seata client/server version: 1.8.0
Database version: 8.0.29

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions