Skip to content

Commit

Permalink
Issue ReactiveX#571: Spring Boot HealthIndicators use the registries now
Browse files Browse the repository at this point in the history
  • Loading branch information
dlsrb6342 authored and RobWin committed Aug 26, 2019
1 parent ab93819 commit f8d0e5a
Show file tree
Hide file tree
Showing 30 changed files with 488 additions and 329 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class RateLimiterConfigurationProperties {

private Map<String, InstanceProperties> instances = new HashMap<>();
private Map<String, InstanceProperties> configs = new HashMap<>();

public Optional<InstanceProperties> findRateLimiterProperties(String name) {
return Optional.ofNullable(instances.get(name));
}

public RateLimiterConfig createRateLimiterConfig(@Nullable InstanceProperties instanceProperties) {
if (instanceProperties == null) {
return RateLimiterConfig.ofDefaults();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.github.resilience4j.circuitbreaker.autoconfigure;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.configure.*;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent;
Expand Down Expand Up @@ -54,18 +53,12 @@ public CircuitBreakerRegistry circuitBreakerRegistry(EventConsumerRegistry<Circu
// Register the event consumers
circuitBreakerConfiguration.registerEventConsumer(circuitBreakerRegistry, eventConsumerRegistry);

// Register a consumer to hook up any health indicators for circuit breakers after creation. This will catch ones that get
// created beyond initially configured backends.
circuitBreakerRegistry.getEventPublisher().onEntryAdded(event -> createHealthIndicatorForCircuitBreaker(event.getAddedEntry(), circuitBreakerProperties));

// Initialize backends that were initially configured.
circuitBreakerConfiguration.initCircuitBreakerRegistry(circuitBreakerRegistry);

return circuitBreakerRegistry;
}

protected abstract void createHealthIndicatorForCircuitBreaker(CircuitBreaker circuitBreaker, CircuitBreakerConfigurationProperties circuitBreakerProperties);

@Bean
@ConditionalOnMissingBean
@Conditional(value = {AspectJOnClasspathCondition.class})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.configure.CircuitBreakerConfigurationProperties;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;

import java.util.Optional;
import java.util.Map;
import java.util.stream.Collectors;

/**
* A Spring Boot health indicators which adds the state of a CircuitBreaker and it's metrics to the health endpoints
*/
public class CircuitBreakerHealthIndicator implements HealthIndicator {
public class CircuitBreakersHealthIndicator implements HealthIndicator {

private static final String FAILURE_RATE = "failureRate";
private static final String SLOW_CALL_RATE = "slowCallRate";
Expand All @@ -37,20 +41,35 @@ public class CircuitBreakerHealthIndicator implements HealthIndicator {
private static final String SLOW_CALLS = "slowCalls";
private static final String NOT_PERMITTED = "notPermittedCalls";
private static final String STATE = "state";
private final CircuitBreaker circuitBreaker;

public CircuitBreakerHealthIndicator(CircuitBreaker circuitBreaker) {
this.circuitBreaker = circuitBreaker;
private final CircuitBreakerRegistry circuitBreakerRegistry;
private final CircuitBreakerConfigurationProperties circuitBreakerProperties;
private final HealthAggregator healthAggregator;

public CircuitBreakersHealthIndicator(CircuitBreakerRegistry circuitBreakerRegistry,
CircuitBreakerConfigurationProperties circuitBreakerProperties,
HealthAggregator healthAggregator) {
this.circuitBreakerRegistry = circuitBreakerRegistry;
this.circuitBreakerProperties = circuitBreakerProperties;
this.healthAggregator = healthAggregator;
}

@Override
public Health health() {
return Optional.of(circuitBreaker)
.map(this::mapBackendMonitorState)
.orElse(Health.up().build());
Map<String, Health> healths = circuitBreakerRegistry.getAllCircuitBreakers().toJavaStream()
.filter(this::isRegisterHealthIndicator)
.collect(Collectors.toMap(CircuitBreaker::getName, CircuitBreakersHealthIndicator::mapBackendMonitorState));

return healthAggregator.aggregate(healths);
}

private boolean isRegisterHealthIndicator(CircuitBreaker circuitBreaker) {
return circuitBreakerProperties.findCircuitBreakerProperties(circuitBreaker.getName())
.map(io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigurationProperties.InstanceProperties::getRegisterHealthIndicator)
.orElse(true);
}

private Health mapBackendMonitorState(CircuitBreaker circuitBreaker) {
private static Health mapBackendMonitorState(CircuitBreaker circuitBreaker) {
switch (circuitBreaker.getState()) {
case CLOSED:
return addDetails(Health.up(), circuitBreaker).build();
Expand All @@ -63,7 +82,7 @@ private Health mapBackendMonitorState(CircuitBreaker circuitBreaker) {
}
}

private Health.Builder addDetails(Health.Builder builder, CircuitBreaker circuitBreaker) {
private static Health.Builder addDetails(Health.Builder builder, CircuitBreaker circuitBreaker) {
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
CircuitBreakerConfig config = circuitBreaker.getCircuitBreakerConfig();
builder.withDetail(FAILURE_RATE, metrics.getFailureRate() + "%")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,57 @@
package io.github.resilience4j.ratelimiter.monitoring.health;

import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.configure.RateLimiterConfigurationProperties;
import io.github.resilience4j.ratelimiter.internal.AtomicRateLimiter;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;

public class RateLimiterHealthIndicator implements HealthIndicator {
import java.util.Map;
import java.util.stream.Collectors;

private final RateLimiter rateLimiter;
private final long timeoutInNanos;
public class RateLimitersHealthIndicator implements HealthIndicator {

public RateLimiterHealthIndicator(RateLimiter rateLimiter) {
this.rateLimiter = rateLimiter;
this.timeoutInNanos = rateLimiter.getRateLimiterConfig().getTimeoutDuration().toNanos();
private final RateLimiterRegistry rateLimiterRegistry;
private final RateLimiterConfigurationProperties rateLimiterProperties;
private final HealthAggregator healthAggregator;

public RateLimitersHealthIndicator(RateLimiterRegistry rateLimiterRegistry,
RateLimiterConfigurationProperties rateLimiterProperties,
HealthAggregator healthAggregator) {
this.rateLimiterRegistry = rateLimiterRegistry;
this.rateLimiterProperties = rateLimiterProperties;
this.healthAggregator = healthAggregator;
}

@Override
public Health health() {
Map<String, Health> healths = rateLimiterRegistry.getAllRateLimiters().toJavaStream()
.filter(this::isRegisterHealthIndicator)
.collect(Collectors.toMap(RateLimiter::getName, this::mapRateLimiterHealth));

return healthAggregator.aggregate(healths);
}

private boolean isRegisterHealthIndicator(RateLimiter rateLimiter) {
return rateLimiterProperties.findRateLimiterProperties(rateLimiter.getName())
.map(io.github.resilience4j.common.ratelimiter.configuration.RateLimiterConfigurationProperties.InstanceProperties::getRegisterHealthIndicator)
.orElse(true);
}

private Health mapRateLimiterHealth(RateLimiter rateLimiter) {
RateLimiter.Metrics metrics = rateLimiter.getMetrics();
int availablePermissions = metrics.getAvailablePermissions();
int numberOfWaitingThreads = metrics.getNumberOfWaitingThreads();
long timeoutInNanos = rateLimiter.getRateLimiterConfig().getTimeoutDuration().toNanos();

if (availablePermissions > 0 || numberOfWaitingThreads == 0) {
return rateLimiterHealth(Status.UP, availablePermissions, numberOfWaitingThreads);
}
if (rateLimiter instanceof AtomicRateLimiter) {
AtomicRateLimiter atomicRateLimiter = (AtomicRateLimiter) this.rateLimiter;
AtomicRateLimiter atomicRateLimiter = (AtomicRateLimiter) rateLimiter;
AtomicRateLimiter.AtomicRateLimiterMetrics detailedMetrics = atomicRateLimiter.getDetailedMetrics();
if (detailedMetrics.getNanosToWait() > timeoutInNanos) {
return rateLimiterHealth(Status.DOWN, availablePermissions, numberOfWaitingThreads);
Expand All @@ -49,10 +75,10 @@ public Health health() {
return rateLimiterHealth(Status.UNKNOWN, availablePermissions, numberOfWaitingThreads);
}

private Health rateLimiterHealth(Status status, int availablePermissions, int numberOfWaitingThreads) {
private static Health rateLimiterHealth(Status status, int availablePermissions, int numberOfWaitingThreads) {
return Health.status(status)
.withDetail("availablePermissions", availablePermissions)
.withDetail("numberOfWaitingThreads", numberOfWaitingThreads)
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.github.resilience4j.bulkhead.ThreadPoolBulkheadRegistry;
import io.github.resilience4j.bulkhead.autoconfigure.AbstractBulkheadConfigurationOnMissingBean;
import io.github.resilience4j.bulkhead.configure.BulkheadConfigurationProperties;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.autoconfigure.AbstractCircuitBreakerConfigurationOnMissingBean;
import io.github.resilience4j.circuitbreaker.configure.CircuitBreakerConfigurationProperties;
Expand Down Expand Up @@ -93,10 +92,6 @@ public CircuitBreakerConfig(CircuitBreakerConfigurationProperties circuitBreaker
super(circuitBreakerProperties);
}

@Override
protected void createHealthIndicatorForCircuitBreaker(CircuitBreaker circuitBreaker, CircuitBreakerConfigurationProperties circuitBreakerProperties) {

}
}

class RetryConfigurationOnMissingBean extends AbstractRetryConfigurationOnMissingBean {
Expand Down

This file was deleted.

Loading

0 comments on commit f8d0e5a

Please sign in to comment.