CircuitBreakersHealthIndicator implements HealthIndicator { @Override public Health health() { Map<String, Health> healths = circuitBreakerRegistry.getAllCircuitBreakers().toJavaStream() .filter(this::isRegisterHealthIndicator) .collect(Collectors.toMap(CircuitBreaker::getName, this::mapBackendMonitorState)); Status status = this.statusAggregator.getAggregateStatus(healths.values().stream().map(Health::getStatus).collect(Collectors.toSet())); return Health.status(status).withDetails(healths).build(); } CircuitBreakersHealthIndicator(CircuitBreakerRegistry circuitBreakerRegistry,
                                          CircuitBreakerConfigurationProperties circuitBreakerProperties,
                                          StatusAggregator statusAggregator); @Override Health health();  }
@Test public void healthMetricsAndConfig() { CircuitBreakerConfig config = mock(CircuitBreakerConfig.class); CircuitBreakerRegistry registry = mock(CircuitBreakerRegistry.class); CircuitBreaker.Metrics metrics = mock(CircuitBreaker.Metrics.class); CircuitBreaker circuitBreaker = mock(CircuitBreaker.class); CircuitBreakerConfigurationProperties.InstanceProperties instanceProperties = mock(CircuitBreakerConfigurationProperties.InstanceProperties.class); CircuitBreakerConfigurationProperties circuitBreakerProperties = mock( CircuitBreakerConfigurationProperties.class); CircuitBreakersHealthIndicator healthIndicator = new CircuitBreakersHealthIndicator(registry, circuitBreakerProperties, new SimpleStatusAggregator()); when(config.getFailureRateThreshold()).thenReturn(30f); when(metrics.getFailureRate()).thenReturn(20f); when(metrics.getSlowCallRate()).thenReturn(20f); when(config.getSlowCallRateThreshold()).thenReturn(50f); when(metrics.getNumberOfBufferedCalls()).thenReturn(100); when(metrics.getNumberOfFailedCalls()).thenReturn(20); when(metrics.getNumberOfSlowCalls()).thenReturn(20); when(metrics.getNumberOfNotPermittedCalls()).thenReturn(0L); when(registry.getAllCircuitBreakers()).thenReturn(Array.of(circuitBreaker)); when(circuitBreaker.getName()).thenReturn("test"); when(circuitBreakerProperties.findCircuitBreakerProperties("test")) .thenReturn(Optional.of(instanceProperties)); when(instanceProperties.getRegisterHealthIndicator()).thenReturn(true); when(instanceProperties.getAllowHealthIndicatorToFail()).thenReturn(true); when(circuitBreaker.getMetrics()).thenReturn(metrics); when(circuitBreaker.getCircuitBreakerConfig()).thenReturn(config); when(circuitBreaker.getState()).thenReturn(CLOSED, OPEN, HALF_OPEN, CLOSED); Health health = healthIndicator.health(); then(health.getStatus()).isEqualTo(Status.UP); then(health.getDetails()).containsKey("test"); then(health.getDetails().get("test")).isInstanceOf(Health.class); then(((Health) health.getDetails().get("test")).getDetails()) .contains( entry("failureRate", "20.0%"), entry("slowCallRate", "20.0%"), entry("slowCallRateThreshold", "50.0%"), entry("failureRateThreshold", "30.0%"), entry("bufferedCalls", 100), entry("slowCalls", 20), entry("failedCalls", 20), entry("notPermittedCalls", 0L) ); }
@Test public void testHealthStatus() { CircuitBreaker openCircuitBreaker = mock(CircuitBreaker.class); CircuitBreaker halfOpenCircuitBreaker = mock(CircuitBreaker.class); CircuitBreaker closeCircuitBreaker = mock(CircuitBreaker.class); Map<CircuitBreaker.State, CircuitBreaker> expectedStateToCircuitBreaker = new HashMap<>(); expectedStateToCircuitBreaker.put(OPEN, openCircuitBreaker); expectedStateToCircuitBreaker.put(HALF_OPEN, halfOpenCircuitBreaker); expectedStateToCircuitBreaker.put(CLOSED, closeCircuitBreaker); CircuitBreakerConfigurationProperties.InstanceProperties instanceProperties = mock(CircuitBreakerConfigurationProperties.InstanceProperties.class); CircuitBreakerConfigurationProperties circuitBreakerProperties = mock( CircuitBreakerConfigurationProperties.class); CircuitBreakerRegistry registry = mock(CircuitBreakerRegistry.class); CircuitBreakerConfig config = mock(CircuitBreakerConfig.class); CircuitBreaker.Metrics metrics = mock(CircuitBreaker.Metrics.class); when(registry.getAllCircuitBreakers()).thenReturn(Array.ofAll(expectedStateToCircuitBreaker.values())); boolean allowHealthIndicatorToFail = true; expectedStateToCircuitBreaker.forEach( (state, circuitBreaker) -> setCircuitBreakerWhen(state, circuitBreaker, config, metrics, instanceProperties, circuitBreakerProperties, allowHealthIndicatorToFail)); CircuitBreakersHealthIndicator healthIndicator = new CircuitBreakersHealthIndicator(registry, circuitBreakerProperties, new SimpleStatusAggregator()); Health health = healthIndicator.health(); then(health.getStatus()).isEqualTo(Status.DOWN); then(health.getDetails()).containsKeys(OPEN.name(), HALF_OPEN.name(), CLOSED.name()); assertState(OPEN, Status.DOWN, health.getDetails()); assertState(HALF_OPEN, new Status("CIRCUIT_HALF_OPEN"), health.getDetails()); assertState(CLOSED, Status.UP, health.getDetails()); }
@Test public void healthIndicatorMaxImpactCanBeOverridden() { CircuitBreaker openCircuitBreaker = mock(CircuitBreaker.class); CircuitBreaker halfOpenCircuitBreaker = mock(CircuitBreaker.class); CircuitBreaker closeCircuitBreaker = mock(CircuitBreaker.class); Map<CircuitBreaker.State, CircuitBreaker> expectedStateToCircuitBreaker = new HashMap<>(); expectedStateToCircuitBreaker.put(OPEN, openCircuitBreaker); expectedStateToCircuitBreaker.put(HALF_OPEN, halfOpenCircuitBreaker); expectedStateToCircuitBreaker.put(CLOSED, closeCircuitBreaker); CircuitBreakerConfigurationProperties.InstanceProperties instanceProperties = mock(CircuitBreakerConfigurationProperties.InstanceProperties.class); CircuitBreakerConfigurationProperties circuitBreakerProperties = mock(CircuitBreakerConfigurationProperties.class); CircuitBreakerRegistry registry = mock(CircuitBreakerRegistry.class); CircuitBreakerConfig config = mock(CircuitBreakerConfig.class); CircuitBreaker.Metrics metrics = mock(CircuitBreaker.Metrics.class); when(registry.getAllCircuitBreakers()).thenReturn(Array.ofAll(expectedStateToCircuitBreaker.values())); boolean allowHealthIndicatorToFail = false; expectedStateToCircuitBreaker.forEach( (state, circuitBreaker) -> setCircuitBreakerWhen(state, circuitBreaker, config, metrics, instanceProperties, circuitBreakerProperties, allowHealthIndicatorToFail)); CircuitBreakersHealthIndicator healthIndicator = new CircuitBreakersHealthIndicator(registry, circuitBreakerProperties, new SimpleStatusAggregator()); Health health = healthIndicator.health(); then(health.getStatus()).isEqualTo(Status.UP); then(health.getDetails()).containsKeys(OPEN.name(), HALF_OPEN.name(), CLOSED.name()); assertState(OPEN, new Status("CIRCUIT_OPEN"), health.getDetails()); assertState(HALF_OPEN, new Status("CIRCUIT_HALF_OPEN"), health.getDetails()); assertState(CLOSED, Status.UP, health.getDetails()); }