Missing metrics when programmatically creating a circuitbreaker - spring-boot

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

Related

Spring integration properties for Kafka

While trying to use listener config properties in application.yml, I am facing an issue where the KafkaListener annotated method is not invoked at all if I use the application.yml config(listener.type= batch). It only gets invoked when I explicitly set setBatchListener to true in code. Here is my code and configuration.
Consumer code:
#KafkaListener(containerFactory = "kafkaListenerContainerFactory",
topics = "${spring.kafka.template.default-topic}",
groupId = "${spring.kafka.consumer.group-id}")
public void receive(List<ConsumerRecord<String,byte[]>> consumerRecords,Acknowledgment acknowledgment){
processor.process(consumerRecords,acknowledgment);
}
application.yml:
listener:
missing-topics-fatal: false
type: batch
ack-mode: manual
Consumer configuration:
ConcurrentKafkaListenerContainerFactory<String, String> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(
new DefaultKafkaConsumerFactory<>(kafkaProperties.buildConsumerProperties()));
factory.setErrorHandler(new SeekToCurrentErrorHandler( new UpdateMessageErrorHandler(),new FixedBackOff(idleEventInterval,maxFailures)));
final ContainerProperties properties = factory.getContainerProperties();
properties.setIdleBetweenPolls(idleBetweenPolls);
properties.setIdleEventInterval(idleEventInterval);
return factory;
}
If I'm not mistaken, by using the ConcurrentKafkaListenerContainerFactory builder in your configuration you're essentially overriding a piece of code that is usually executed within ConcurrentKafkaListenerContainerFactoryConfigurer class within spring autoconfiguration package:
if (properties.getType().equals(Type.BATCH)) {
factory.setBatchListener(true);
factory.setBatchErrorHandler(this.batchErrorHandler);
} else {
factory.setErrorHandler(this.errorHandler);
}
Since it's hardcoded in your application.yaml file anyway, why is it a bad thing for it to be configured in your #Configuration file?

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));

Spring Boot custom Kubernetes readiness probe

I want to implement custom logic to determine readiness for my pod, and I went over this: https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.kubernetes-probes.external-state and they mention an example property:
management.endpoint.health.group.readiness.include=readinessState,customCheck
Question is - how do I override customCheck?
In my case I want to use HTTP probes, so the yaml looks like:
readinessProbe:
initialDelaySeconds: 10
periodSeconds: 10
httpGet:
path: /actuator/health
port: 12345
So then again - where and how should I apply logic that would determine when the app is ready (just like the link above, i'd like to rely on an external service in order for it to be ready)
customCheck is a key for your custom HealthIndicator. The key for a given HealthIndicator is the name of the bean without the HealthIndicator suffix
You can read:
https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.health.writing-custom-health-indicators
You are defining readinessProbe, so probably hiting /actuator/health/readiness is a better choice.
public class CustomCheckHealthIndicator extends AvailabilityStateHealthIndicator {
private final YourService yourService;
public CustomCheckHealthIndicator(ApplicationAvailability availability, YourService yourService) {
super(availability, ReadinessState.class, (statusMappings) -> {
statusMappings.add(ReadinessState.ACCEPTING_TRAFFIC, Status.UP);
statusMappings.add(ReadinessState.REFUSING_TRAFFIC, Status.OUT_OF_SERVICE);
});
this.yourService = yourService;
}
#Override
protected AvailabilityState getState(ApplicationAvailability applicationAvailability) {
if (yourService.isInitCompleted()) {
return ReadinessState.ACCEPTING_TRAFFIC;
} else {
return ReadinessState.REFUSING_TRAFFIC;
}
}
}

Get Instance of circuit breaker from configuration file

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;

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