Get Instance of circuit breaker from configuration file - spring-boot

This is my configuration file.
resilience4j.circuitbreaker:
instances:
backendB:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 10
permittedNumberOfCallsInHalfOpenState: 3
waitDurationInOpenState: 5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
I am trying to create bean of my feign client using Resilience4jFeign but the circuit breaker object is initialized with default configuration as the name suggest CircuitBreaker.ofDefaults. I can't find any ways to get my instance of circuit breaker from configuration to an object.
#Bean
public CommunicationServiceProxy communicationServiceProxy(){
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendB");
FeignDecorators decorators = FeignDecorators.builder()
.withCircuitBreaker(circuitBreaker)
.withFallbackFactory(CommunicationFallBack::new)
.build();
return Resilience4jFeign
.builder(decorators)
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.target(CommunicationServiceProxy.class, "http://localhost:8081");
}

I found the solution and it was using the CircuitBreakerRegistry.
Instead of creating registry using
CircuitBreakerRegistry.ofDefaults()
one need to autowired them.
#Autowired
private CircuitBreakerRegistry circuitBreakerRegistry;

Related

Trying to create Retry object from application.yml

I'm relatively new to Spring-Boot + resilience4j and I'm trying to create a Retry object using the config in my .yml file. Currently I'm trying to decorate a Mono with very similar syntax to what is given in the docs:
Retry retry = Retry.of("backendName", sampleRetryConfig);
Mono.fromCallable(backendService::doSomething)
.transformDeferred(RetryOperator.of(retry))
In the above code snippet I'm explicitly declaring the sampleRetryConfig in the code and using that to create my Retry, but is there a way for me to create the Retry object using the RetryConfig pulled from my .yml file?
resilience4j.retry:
instances:
apiRetry:
maxAttempts: 3
waitDuration: 2s
enableExponentialBackoff: true
ignoreExceptions:
- example.exceptions
Support seems to be there for using the #Retry annotation, but I haven't found anything about support for what I'm trying to do.
Late answer but here's what I ended up doing. Using the RetryRegistry and declaring the Retry objects as beans I was able to make it work.
Here's the contents of the .yml
resilience4j:
retry:
api-path:
maxAttempts: 1
waitDuration: 1s
ignoreExceptions:
And the class where the retry beans were created:
private final RetryRegistry retryRegistry;
#Bean
public Retry apiPathRetry() {
return retryRegistry.retry("api-path");
}
Then finally, using the objects in a class.
return Mono.fromSupplier(() -> method)
.flatMap(genericData-> {business logic})
.transformDeferred(RetryOperator.of(apiPathRetry));

Change timeout for Spring Cloud Circuit Breaker at runtime?

I'm using Spring Cloud Circuit Breaker 2.0.0 (resilience4j implementation) for circuit breaking and timeouts in my application. I've created the following configuration:
#Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory ->
factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(10)).build())
.circuitBreakerConfig(..)
.build());
}
Now I want to write an integration test to verify that my behavior is correct when a timeout occurs. For this to work, I'd like to temporarily change the timeout duration specified in the configuration above to something like 1 millisecond instead of 10 seconds.
So my question is: How can I change the value of the timeout of the TimeLimiterConfig(temporarily) when I'm writing a Spring Boot integration test?
You can use the #Value Spring annotation that retrieves the value at a configuration file from your resource folder src/main/resources/common.properties.
#Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer(
#Value("${duration.milli:600}") int durationMilli) {
return factory ->
factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMilli(durationMilli)).build())
.circuitBreakerConfig(..)
.build());
}
Then you set the value at src/main/resources/common.properties
duration.milli=600
When you are doing your test you can configure another resource file at the test folder src/test/resources/common.properties with a different value.
duration.milli=1

resilience4j Spring Boot 2

Trying out a simple Spring Boot 2 + Resilience4j project.
But facing an issue that the circuit breaker is always CLOSED though the host application is down.
Service class
#Autowired
private RestTemplate restTemplate;
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#CircuitBreaker(name = "mainService", fallbackMethod="testFallBack")
public ResponseEntity<String> invokeService(int i) {
return restTemplate.exchange(
"http://localhost:9092/", // This service is always down
HttpMethod.GET,
null,
String.class
);
}
private ResponseEntity<String> testFallBack(int i, Exception e) {
return new ResponseEntity<String>("In fallback method", HttpStatus.INTERNAL_SERVER_ERROR);
}
Resilience4J Config
management.endpoint.health.show-details: always
management.health.circuitbreakers.enabled: true
resilience4j:
circuitbreaker:
configs:
default:
registerHealthIndicator: true
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
failureRateThreshold: 50
eventConsumerBufferSize: 10
instances:
mainService:
baseConfig: default
The Service is being called multiple times from the Controller and I expect it to fallback after minimum 5 calls but the circuit breaker is always CLOSED and for each call from controller the host service is being called and up with Connection refused.
Dependencies: spring-boot-starter-web, resilience4j-spring-boot2, spring-aop, spring-boot-starter-actuator
Earlier I tried out programmatic approach using CircuitBreakerRegistry and Decorator Function which works as expected.
Actually, you misunderstand the circuit breaker parameters. See the documentation:
minimumNumberOfCalls, default: 100
Configures the minimum number of calls which are required (per sliding window period) before the CircuitBreaker can calculate the error rate or slow call rate.
For example, if minimumNumberOfCalls is 10, then at least 10 calls must be recorded, before the failure rate can be calculated.
If only 9 calls have been recorded the CircuitBreaker will not transition to open even if all 9 calls have failed.
slidingWindowSize, default: 100
Configures the size of the sliding window which is used to record the outcome of calls when the CircuitBreaker is closed.
In your configuration, there is
minimumNumberOfCalls: 5
slidingWindowSize: 100 ## implicitly, because you have not set this parameters
And you
expect it to fallback after minimum 5 calls
However, your circuit breaker opens after 100 failures, not after 5.

Missing metrics when programmatically creating a circuitbreaker

I want to define a circuitbreak with a programming approach so I did:
#Configuration
public class MyCircuitBreakerConfig {
#Bean
public CircuitBreakerRegistry myRegistry() {
CircuitBreakerRegistry registry = CircuitBreakerRegistry.ofDefaults();
registry.circuitBreaker("mycircuit", circuitConfig());
return registry;
}
Problem is that, even though it works correctly, I get the following in metrics:
"components" : {
"circuitBreakers" : {
"status" : "UNKNOWN"
}
While, if I define it in my properties file:
resilience4j:
circuitbreaker:
configs:
myconfig:
...
instances:
mycircuit:
base-config: myconfig
I can see it. What could the problem be?
I'm using the resilience4j-spring-boot2 dependency.
You must not create your own CircuitBreakerRegistry.
The Spring Boot AutoConfiguration creates an instance which you should use. If you need it, just inject (autowire) the existing CircuitBreakerRegistry into your code.
You can override the defaults as follows
resilience4j.circuitbreaker:
configs:
default:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 10
waitDurationInOpenState: 10000
failureRateThreshold: 60
eventConsumerBufferSize: 10

How to configure LoggingMeterRegistry step duration in Spring Boot 2.x?

I am trying to configure the LoggingMeterRegistry to log metrics for my Spring Boot 2.1.6 application. I want the metrics to be logged every hour.
In my application.yml, I've the following configured
management:
metrics:
export:
logging:
enabled: true
step: 60m
But in the logs I see the metrics being logged every minute. I've tried the other variation for the property key as well e.g.
management.metrics.export.logging:
enabled: true
step: 60m
I have also tried various formats for the duration string e.g. 1h, PT60M but with no success. The metrics are logged at 1 minute intervals.
I was looking at the code here StepDurationConverterTest and here StepDurationConverter that converts the step duration String to a Duration object and looks like both formats 60m and 1h should work.
Any ideas why I can't seem to change the logging interval?
I think the problem here is there's no
org.springframework.boot.actuate.autoconfigure.metrics.export.logging
package like there is for other MeterRegistrys (eg org.springframework.boot.actuate.autoconfigure.metrics.export.jmx).
Ie theres no auto configuration for the properties in Spring Boot. This is probably because the LoggingMeterRegistry is marked as #Incubating
You need to manually configure the LoggingMeterRegistry as a bean and create your own #ConfigurationProperties LoggingProperties and LoggingPropertiesConfigAdapter to get this to work. Or just hardcode the step period you want.
To configure step count duration in micrometer:
Please follow below step:
#Configuration
public class LoggingMeterRegistryConfig {
#Bean
public LoggingMeterRegistry loggingMeterRegistry() {
LoggingRegistryConfig config = new LoggingRegistryConfig() {
#Override
public String get(String s) {
return null;
}
#Override
public Duration step() {
return Duration.ofMinutes(2);
}
};
return LoggingMeterRegistry.builder(config).clock(Clock.SYSTEM).threadFactory(new NamedThreadFactory("logging-metrics-publisher")).build();
}
}
The following #Bean supplies config from Spring Environment allowing you to specify a property logging.step: 1h to get your desired period.
#Bean
LoggingMeterRegistry loggingMeterRegistry(Environment env) {
LoggingRegistryConfig springBasedConfig = prop -> env.getProperty(prop, String.class);
return new LoggingMeterRegistry(springBasedConfig, Clock.SYSTEM);
}

Resources