-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Description
Ⅰ. 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