incubator-seata icon indicating copy to clipboard operation
incubator-seata copied to clipboard

bugfix: fix the failure of @BusinessActionContextParamete annotation …

Open TakeActionNow2019 opened this issue 1 year ago • 22 comments

Ⅰ. Describe what this PR did fix the failure of @BusinessActionContextParamete annotation to set parameters into io.seata.rm.tcc.api.BusinessActionContext at TCC mode

Ⅱ. Does this pull request fix one issue? fixes #6454

Ⅲ. Why don't you add test cases (unit test/integration test)? Ⅳ. Describe how to verify it Ⅴ. Special notes for reviews

TakeActionNow2019 avatar Apr 10 '24 18:04 TakeActionNow2019

May I know what is going on? How can I merge my pull request to the target branch?

TakeActionNow2019 avatar Apr 11 '24 14:04 TakeActionNow2019

May I know what is going on? How can I merge my pull request to the target branch?

According to the community CONTRIBUTING.md, you may not merge PR directly. After someone who has write permission reviews and approves, and then it can be merged.

ptyin avatar Apr 14 '24 15:04 ptyin

Can you shed some lights on why changing targetBean to invocation.getTarget() can sort it out? The latter can be subclass of the former, is that what you are tring to solve? As the picture shows, if we just want to find the annotation @TwoPhaseBusinessAction on the interfaces of the invoked TCC try method, invocation.getTarget() is good enough to handle it. Its proxy targetBean only increases the complexity. The @TwoPhaseBusinessAction in my demo project is on the TCC try method of interface alibaba.cloud.spring.provider.service.StockService. image image image

TakeActionNow2019 avatar Apr 15 '24 17:04 TakeActionNow2019

Can you shed some lights on why changing targetBean to invocation.getTarget() can sort it out? The latter can be subclass of the former, is that what you are tring to solve? As the picture shows, if we just want to find the annotation @TwoPhaseBusinessAction on the interfaces of the invoked TCC try method, invocation.getTarget() is good enough to handle it. Its proxy targetBean only increases the complexity. The @TwoPhaseBusinessAction in my demo project is on the TCC try method of interface alibaba.cloud.spring.provider.service.StockService. image image image

As shown in the figure you provided, both targetBean and invocation.getTarget() can find the deduct method. So, this PR is a complexity optimization not a bugfix for #6454, right?

ptyin avatar Apr 17 '24 05:04 ptyin

That makes sense for me. What do you think @funky-eyes?

ptyin avatar Apr 17 '24 05:04 ptyin

That makes sense for me. What do you think @funky-eyes?

I agree with you.

funky-eyes avatar Apr 17 '24 08:04 funky-eyes

Can you shed some lights on why changing targetBean to invocation.getTarget() can sort it out? The latter can be subclass of the former, is that what you are tring to solve? As the picture shows, if we just want to find the annotation @TwoPhaseBusinessAction on the interfaces of the invoked TCC try method, invocation.getTarget() is good enough to handle it. Its proxy targetBean only increases the complexity. The @TwoPhaseBusinessAction in my demo project is on the TCC try method of interface alibaba.cloud.spring.provider.service.StockService. image image image

As shown in the figure you provided, both targetBean and invocation.getTarget() can find the deduct method. So, this PR is a complexity optimization not a bugfix for #6454, right?

@ptyin It is really a bugfix. I do the optimization by the way. There several bugs here: 1.The RuntimeException is thrown too early. It should thrown later outside the for-loop. 2.The method initCommonFenceCleanTask may not execute in some scenarios. The early thrown RuntimeException may also lead to it. There are also other scenarios. 3. Last but most importantly, the later executing method org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler#fetchActionRequestContext needs its parameter variable "method " with @TwoPhaseBusinessAction. In my demo project, if variable "method" stands for interface StockService annotated by @TwoPhaseBusinessAction, fetchActionRequestContext will successfully get the parameters annotated by @BusinessActionContextParameter and put them in context. If variable "method" stands for StockServiceImpl#deduct whose interface method is annotated by @TwoPhaseBusinessAction, fetchActionRequestContext will fail to get all the parameters annotated by @BusinessActionContextParameter. What I do in the bugfix is to get the exact method with @TwoPhaseBusinessAction image image image

TakeActionNow2019 avatar Apr 17 '24 16:04 TakeActionNow2019

image

TakeActionNow2019 avatar Apr 17 '24 16:04 TakeActionNow2019

The third point, are you trying to express that when using @BusinessActionContextParameter in the interface and @TwoPhaseBusinessAction in the implementation class, it leads to the invalidation of @BusinessActionContextParameter?

funky-eyes avatar Apr 18 '24 08:04 funky-eyes

The third point, are you trying to express that when using @BusinessActionContextParameter in the interface and @TwoPhaseBusinessAction in the implementation class, it leads to the invalidation of @BusinessActionContextParameter?

Nah. What I described in the third point is that a variable "method" that exactly stands for the TCC try method annnotated by @TwoPhaseBusinessAction and @BusinessActionContextParameter shoud be passed to org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler#fetchActionRequestContext. Or fetchActionRequestContext will fail to get the parameters annotated by @BusinessActionContextParameter.

@TwoPhaseBusinessAction and @BusinessActionContextParameter on my demo project: image

alibaba.cloud.spring.provider.service.StockService.deduct instead of alibaba.cloud.spring.provider.service.StockServiceImpl.deduct should be passed to fetchActionRequestContext. image

TakeActionNow2019 avatar Apr 18 '24 15:04 TakeActionNow2019

What I did in the bugfix is to get the exact method annotated by @TwoPhaseBusinessAction and @BusinessActionContextParameter. (I suppose that it is a convention to put them together on a TCC try method of interface, at least putting them together) @ptyin @funky-eyes

TakeActionNow2019 avatar Apr 18 '24 15:04 TakeActionNow2019

What I did in the bugfix is to get the exact method annotated by @TwoPhaseBusinessAction and @BusinessActionContextParameter. (I suppose that it is a convention to put them together on a TCC try method of interface, at least putting them together) @ptyin @funky-eyes

我们未来希望注解都是在实现类中,而不是在接口上,目前的实现中我们之前就发现了子类会覆盖父类,导致最终的参数读取行为不准。由于tcc的特殊性,他的接口可能是由provider提供,如果注解都写在接口上时,会导致consumer与provider都进行了方法切面等行为,这是不可取的,经过社区的会议,未来会不允许注解在接口上,而是需要再实现类上

In the future, we prefer annotations to be placed in implementation classes rather than interfaces. In our current implementation, we have encountered issues where subclasses override parent classes, leading to inaccurate parameter reading behavior. Due to the unique nature of TCC, its interfaces may be provided by the provider. If annotations are placed on interfaces, it will result in both the consumer and the provider performing method interception, which is undesirable. Following discussions within the community, annotations will not be allowed on interfaces in the future, and instead, they will need to be placed on implementation classes.

https://github.com/apache/incubator-seata/issues/6235

funky-eyes avatar Apr 22 '24 01:04 funky-eyes

What I did in the bugfix is to get the exact method annotated by @TwoPhaseBusinessAction and @BusinessActionContextParameter. (I suppose that it is a convention to put them together on a TCC try method of interface, at least putting them together) @ptyin @funky-eyes

我们未来希望注解都是在实现类中,而不是在接口上,目前的实现中我们之前就发现了子类会覆盖父类,导致最终的参数读取行为不准。由于tcc的特殊性,他的接口可能是由provider提供,如果注解都写在接口上时,会导致consumer与provider都进行了方法切面等行为,这是不可取的,经过社区的会议,未来会不允许注解在接口上,而是需要再实现类上

In the future, we prefer annotations to be placed in implementation classes rather than interfaces. In our current implementation, we have encountered issues where subclasses override parent classes, leading to inaccurate parameter reading behavior. Due to the unique nature of TCC, its interfaces may be provided by the provider. If annotations are placed on interfaces, it will result in both the consumer and the provider performing method interception, which is undesirable. Following discussions within the community, annotations will not be allowed on interfaces in the future, and instead, they will need to be placed on implementation classes.

#6235

Make sense! Thanks for your patience! Could you please help me merge this pull request? @funky-eyes @ptyin

TakeActionNow2019 avatar Apr 22 '24 16:04 TakeActionNow2019

What I did in the bugfix is to get the exact method annotated by @TwoPhaseBusinessAction and @BusinessActionContextParameter. (I suppose that it is a convention to put them together on a TCC try method of interface, at least putting them together) @ptyin @funky-eyes

我们未来希望注解都是在实现类中,而不是在接口上,目前的实现中我们之前就发现了子类会覆盖父类,导致最终的参数读取行为不准。由于tcc的特殊性,他的接口可能是由provider提供,如果注解都写在接口上时,会导致consumer与provider都进行了方法切面等行为,这是不可取的,经过社区的会议,未来会不允许注解在接口上,而是需要再实现类上 In the future, we prefer annotations to be placed in implementation classes rather than interfaces. In our current implementation, we have encountered issues where subclasses override parent classes, leading to inaccurate parameter reading behavior. Due to the unique nature of TCC, its interfaces may be provided by the provider. If annotations are placed on interfaces, it will result in both the consumer and the provider performing method interception, which is undesirable. Following discussions within the community, annotations will not be allowed on interfaces in the future, and instead, they will need to be placed on implementation classes. #6235

Make sense! Thanks for your patience! Could you please help me merge this pull request? @funky-eyes @ptyin

I will run some tests on this PR, and if the tests pass, I will merge it.

funky-eyes avatar Apr 23 '24 02:04 funky-eyes

image image

It did not fix the issue where BusinessActionContextParameter is ineffective in interfaces

I suppose it is a convetion to put @TwoPhaseBusinessAction and @BusinessActionContextParameter together. May I know where your @TwoPhaseBusinessAction is ? In my bugfix, it makes TCC mode work well in scenarios putting them together on the interface. While it will not be supported in the future.

Here is my demo project. It works well on my side. If possible, upload your code to the repository so that I can have a look. image

TakeActionNow2019 avatar Apr 23 '24 16:04 TakeActionNow2019

@funky-eyes Please help me review it again! Thanks a lot!

TakeActionNow2019 avatar Apr 23 '24 17:04 TakeActionNow2019

我的例子就是上面所说的,当TwoPhaseBusinessAction在实现类中,而BusinessActionContextParameter在接口中时,会读取不到BusinessActionContextParameter相关的参数,我认为6454中描述的是我这种情况,所以无法正确读取到参数。 My example is exactly as mentioned above, where the BusinessActionContextParameter is in the interface while TwoPhaseBusinessAction is in the implementation class. In this scenario, the parameters related to BusinessActionContextParameter cannot be read correctly. I believe that what is described in 6454 is similar to my situation, hence the inability to correctly read the parameters.

funky-eyes avatar Apr 24 '24 01:04 funky-eyes

我的例子就是上面所说的,当TwoPhaseBusinessAction在实现类中,而BusinessActionContextParameter在接口中时,会读取不到BusinessActionContextParameter相关的参数,我认为6454中描述的是我这种情况,所以无法正确读取到参数。 My example is exactly as mentioned above, where the BusinessActionContextParameter is in the interface while TwoPhaseBusinessAction is in the implementation class. In this scenario, the parameters related to BusinessActionContextParameter cannot be read correctly. I believe that what is described in 6454 is similar to my situation, hence the inability to correctly read the parameters.

@funky-eyes As far as I know, The author of issue 6454 has just put the two annotations together on the TCC try method, just as the picture shown below. And I consider it a little weird to put them separately.  ̄□ ̄||

image

TakeActionNow2019 avatar Apr 24 '24 04:04 TakeActionNow2019

https://github.com/apache/incubator-seata/issues/6235 According to 6454, it's not possible to determine whether the user has also added the TwoPhaseBusinessAction annotation in the implementation class. However, based on 6235, it can be inferred that users of 6454 may behave similarly to users of 6235, where the issue arises due to the subclass overriding the superclass, causing the annotation to be ineffective. My proposed solution is to prioritize the subclass, attempting to read the annotation from the superclass method only if the subclass method does not have the annotation. The same approach would be applied to handling parameters. This way, we can effectively resolve the issue.

funky-eyes avatar Apr 24 '24 05:04 funky-eyes

#6235 According to 6454, it's not possible to determine whether the user has also added the TwoPhaseBusinessAction annotation in the implementation class. However, based on 6235, it can be inferred that users of 6454 may behave similarly to users of 6235, where the issue arises due to the subclass overriding the superclass, causing the annotation to be ineffective. My proposed solution is to prioritize the subclass, attempting to read the annotation from the superclass method only if the subclass method does not have the annotation. The same approach would be applied to handling parameters. This way, we can effectively resolve the issue.

I feel you. It is really a best practice to put the two annotations on the TCC try method of the implementation class. Acutally the demo in the official document is as shown below. Usually the users just refer to the demo and find setting parameters to context failed in this way, just like me. o(╯□╰)o So in a sense, this bugfix make it work well for the current seata version. image

TakeActionNow2019 avatar Apr 24 '24 14:04 TakeActionNow2019

@funky-eyes I don't know what's going about this PR. What else do I need to do to merge this PR? Could you tell me? And I have a doubt: Why can you still check issues and PRs during work hours? Don’t you have to work? Or is this what you do for work? O(∩_∩)O

TakeActionNow2019 avatar Apr 24 '24 14:04 TakeActionNow2019

@funky-eyes I don't know what's going about this PR. What else do I need to do to merge this PR? Could you tell me? And I have a doubt: Why can you still check issues and PRs during work hours? Don’t you have to work? Or is this what you do for work? O(∩_∩)O

I plan to consider merging this PR in version 2.2, and I would like it to change the annotation method to a complementary form with priority setting, rather than solely using annotations from the parent class or the subclass. @slievrly @wangliang181230 @wt-better What do you guys think?

funky-eyes avatar Apr 25 '24 01:04 funky-eyes