iAmClever opened a new issue, #6665:
URL: https://github.com/apache/incubator-seata/issues/6665

   Ⅰ. 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


-- 
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]

Reply via email to