spring-cloud / spring-cloud-circuitbreaker

Spring Cloud Circuit Breaker API and Implementations
Apache License 2.0
328 stars 109 forks source link

Spring Boot 2 + resilience4j - fallback method not being called in integration test #170

Closed scurtis-disco closed 8 months ago

scurtis-disco commented 1 year ago

I originally asked this as an SO question and then as in issue in the resilience4j project, and RobWin pointed me over here. To save clicks, I'll copy-paste the full text of the GH issue below.

=== START COPY-🍝 ===

Resilience4j version: 1.7.0

Spring Cloud Starter version: 2.1.0

Java version: 17

I posted an SO question laying out my problem. Initially, I couldn't get the CB instance from the registry, but I solved that issue by importing CircuitBreakerAutoConfiguration.class. Now, the other issue is that the fallback method isn't being invoked. It works when the code is deployed but not in the integration test. I verified by debugging in my IDE that the CB is being created, with the configs I have defined in a test YAML.

resilience4j:
  circuitbreaker:
    instances:
      pmiServiceCircuitBreaker:
        minimumNumberOfCalls: 5
        slidingWindowSize: 10
        slidingWindowType: COUNT_BASED
        failureRateThreshold: 50 # percentage
        slowCallRateThreshold: 100 # percentage for slowCallDurationThreshold
        slowCallDurationThreshold: 200ms # milliseconds, should this be lower?
        permittedNumberOfCallsInHalfOpenState: 5
        waitDurationInOpenState: 1s # seconds

The simple test looks like:

@slf4j
https://github.com/import(
{

            TestConfig.class,
            CircuitBreakerAutoConfiguration.class
    }
)
https://github.com/SpringBootTest(
classes = {
GrpcTestServer.class,
TestGrpcClientConfigSpy.class,
ClassWithCircuitBreaker.class
}
)
@activeprofiles("test")
@ExtendWith(SpringExtension.class)
@testinstance(TestInstance.Lifecycle.PER_CLASS)
public class ClassWithCircuitBreakerTest {

@Autowired
private TestGrpcClientConfigSpy grpcClientConfigSpy;

@Autowired
CircuitBreakerRegistry circuitBreakerRegistry;

@SpyBean
@Autowired
ClassWithCircuitBreaker cwcb;

@DisplayName("ClassWithCircuitBreaker - circuit breaker enabled")
@Test
void testCircuitBreaker_enabled() throws IOException {
    circuitBreakerRegistry.getAllCircuitBreakers().forEach(cb -> {
        log.info("found circuit breaker :: {}", cb.getName());
        log.info("circuit breaker state is :: {}", cb.getState().name());
    });

    int failedCalls = 0;

    Stream.rangeClosed(1,10).forEach(count -> {
        try {
            cwcb.doStuff("blah", "test-id-123");
        } catch(StatusRuntimeException sre) {
            log.warn("exceptiones? {}", sre.getMessage());
        };
    });

    CircuitBreaker cb = circuitBreakerRegistry.circuitBreaker("myCB");
    CircuitBreaker.Metrics metrics = cb.getMetrics();

    log.info("configs :: {}", cb.getCircuitBreakerConfig());
    log.info("failed metrics :: {}", metrics.getNumberOfFailedCalls());
    log.info("success metrics :: {}", metrics.getNumberOfSuccessfulCalls());
    log.info("state after test :: {}", cb.getState().name());
    assertTrue(true);
}
}

The class I am testing is a gRPC client, so the GrpcTestServer class sets up a server and for this test, it's configured to throw a StatusRuntimeException and I see that being logged in the test, but the fallback method is never invoked, and all of the metrics are zero and the circuit stays closed. Again, this works when deployed, it's only the integration test that is not working. Any help is much appreciated.

=== END COPY-🍝 ===

ryanjbaxter commented 1 year ago

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.

scurtis-disco commented 1 year ago

@ryanjbaxter I will try to get to that sometime this week.

spring-cloud-issues commented 1 year 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.

spring-cloud-issues commented 1 year ago

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

scurtis-disco commented 11 months ago

@spring-cloud-issues @ryanjbaxter I have pushed a minimal example to the repo now, that includes a simple protobuf to use as the external service via running mvn compile before running the unit tests.

I have 2 unit tests that log the circuit breaker and its state, and it appears to work correctly (still not sure why it's not working in my real project). HOWEVER, I found a different issue that I don't understand, namely that my custom runtime exception doesn't trigger the fallback method. I confirmed this via logging, and debugging in my Intellij IDE and setting a breakpoint inside the method, and the code never hits that breakpoint.

Any help to understand this is much appreciated.

scurtis-disco commented 10 months ago

Is this going to be re-opened now that there is an example?

guerricmerleHUG commented 10 months ago

we had the same issue and adding this dependency fixed it :

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
scurtis-disco commented 10 months ago

@guerricm

I already have that dependency in the example.

EDIT: that does fix the issue of instantiating the circuit breaker, so we've got that going for us, which is nice. 🤣

scurtis-disco commented 10 months ago

This seems like a good time to point out again, even though it's explicit with the title above, this only affects testing, the real out-in-the-wild code works as expected. I just want to understand the difference between the environment when testing vs. the deployed production code.

ryanjbaxter commented 9 months ago

I don't see a link to the repo in your comment.

spring-cloud-issues commented 9 months 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.

scurtis-disco commented 9 months ago

@ryanjbaxter @spring-cloud-issues my apologies, I thought I had already linked to it earlier in this post.

Here is my example

ryanjbaxter commented 9 months ago

That link gives me a 404

scurtis-disco commented 9 months ago

@ryanjbaxter I have added you as a collaborator to the repo.

ryanjbaxter commented 8 months ago

This is not a minimally project, please make it as simple as possible. In addition you are using versions of Spring Boot and Spring Cloud that are no longer supported. Please recreate a sample that is a barebones as possible that demonstrates the problem using supported versions of Spring Boot and Spring Cloud and provide details of how to use the same to reproduce the problem in the README.

spring-cloud-issues commented 8 months 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.

spring-cloud-issues commented 8 months ago

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.