spring-cloud / spring-cloud-circuitbreaker

Spring Cloud Circuit Breaker API and Implementations
Apache License 2.0
329 stars 110 forks source link

Resilience4j's TimeLimiter triggered after feign response in postConstruct() callback #120

Closed DevDengChao closed 1 year ago

DevDengChao commented 3 years ago

Describe the bug Like the title said. I found that Resilience4j's TimeLimiter always triggered even feign client received response when feign method's return type is not void.

I'm using: OpenJDK 1.8.0_292-b10 and 11.0.11.9-hotspot Spring boot 2.5.2 Spring cloud 2020.0.3

Sample Here: https://github.com/DevDengChao/resilience4j-time-limiter-triggered-after-feign-response

eduardolbueno commented 2 years ago

This is either some race condition with @PostConstruct or an issue with the bean proxies on the Application class. If you move the code to a controller class, it works fine.

DevDengChao commented 2 years ago

@eduardolbueno Thanks, I've updated the sample project and split it into two show case.

  1. Perform Feign request in any component's postConstruct() callback will reproduce this issue. See FeignClientsWarmup class and its test case in the sample project.
  2. Perform Feign request in any controller's request handlers will not reproduce this issue. See RootController class and its test case in the sample project.

Maybe I can perform a one-time async task right after the application started to warm up my Feign clients instead of using the postConstruct() callback.

eduardolbueno commented 2 years ago

If it is a functional requirement of your application then you could try other startup mechanisms, e.g.

https://www.baeldung.com/running-setup-logic-on-startup-in-spring

ryanjbaxter commented 2 years ago

@DevDengChao does this only happen when using OpenFeign?

DevDengChao commented 2 years ago

@DevDengChao does this only happen when using OpenFeign?

Emm, I'm not certain, as I don't know what to test next. 🤣 Do you mean RestTemplate ?

ryanjbaxter commented 2 years ago

Yes you could make a call using RestTemplate and wrap it in a CircuitBreaker.

spring-cloud-issues commented 2 years ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

DevDengChao commented 2 years ago

@ryanjbaxter I'd like to provide you such test cases, but I'm not familiar with RestTemplate and I'm little busy these weeks.

Maybe I'll give it one more try this week.

ryanjbaxter commented 2 years ago

Sounds good, thanks!

gamelike commented 1 year ago

I also find this problem. it will make a feign call during initialization.

ryanjbaxter commented 1 year ago

@gamelike Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

gamelike commented 1 year ago

@ryanjbaxter The demo link : https://github.com/gamelike/spring-circuit-breaker-sample-demo It just show circuit-breaker time out exception. And I put thread-dump.txt in project.

DevDengChao commented 1 year ago

@ryanjbaxter Hi, I finally have some time updating the sample repository, there is a RestTemplateWarmup class now.

I followed https://spring.io/projects/spring-cloud-circuitbreaker#core-concepts this guide to wrap a rest template inside resilience4j.

You can try running the sample app to see rest template works fine with resilience4j but feign clients not.

ryanjbaxter commented 1 year ago

@gamelike @DevDengChao thanks for the samples.

It looks like we are experiencing a bit of a deadlock due to the feign client calls happening curing bean creation.

The feign client calls are blocking waiting for a response.

The circuit breakers are run in a separate thread. The request is made to the remote service, but then Feign is trying to decode the response. This is calling this line https://github.com/spring-cloud/spring-cloud-openfeign/blob/3.1.x/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringDecoder.java#L70

This ends up trying to access a ConcurentHashMap which is currently locked by the bean post processor.

If you use Spring Cloud 2021.0.4-SNAPSHOT and set the property spring.cloud.circuitbreaker.resilience4j.disableThreadPool=true I think things should work. Could you give that a try?

gamelike commented 1 year ago

@ryanjbaxter thanks for your reply.

If you use Spring Cloud 2021.0.4-SNAPSHOT and set the property spring.cloud.circuitbreaker.resilience4j.disableThreadPool=true I think things should work. Could you give that a try?

How i should build 2021.0.4-SNAPSHOT, I'll try. yes, it works.

In prod env, I can't update version to 2021.0.4-SNAPSHOT, is there any other way to solve this problem?

DevDengChao commented 1 year ago

If you use Spring Cloud 2021.0.4-SNAPSHOT and set the property spring.cloud.circuitbreaker.resilience4j.disableThreadPool=true I think things should work. Could you give that a try?

@ryanjbaxter It works. thanks.

ryanjbaxter commented 1 year ago

Thanks @gamelike and @DevDengChao.

If this solution works then we will just have to wait for our next release to take advantage of it. Our next release is planned for the end of this month

gamelike commented 1 year ago

Thanks @ryanjbaxter for the answer.