@Test public void shouldReturnTheSameConsumer() { CircuitBreaker.EventPublisher eventPublisher = circuitBreaker.getEventPublisher(); CircuitBreaker.EventPublisher eventPublisher2 = circuitBreaker.getEventPublisher(); assertThat(eventPublisher).isEqualTo(eventPublisher2); }
@RequestMapping(value = "stream/events/{circuitBreakerName}", produces = MEDIA_TYPE_TEXT_EVENT_STREAM) public SseEmitter getEventsStreamFilteredByCircuitBreakerName(@PathVariable("circuitBreakerName") String circuitBreakerName) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.getAllCircuitBreakers() .find(cb -> cb.getName().equals(circuitBreakerName)) .getOrElseThrow(() -> new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName))); return CircuitBreakerEventEmitter.createSseEmitter(toFlux(circuitBreaker.getEventPublisher())); }
@RequestMapping(value = "stream/events/{circuitBreakerName}/{eventType}", produces = MEDIA_TYPE_TEXT_EVENT_STREAM) public SseEmitter getEventsStreamFilteredByCircuitBreakerNameAndEventType(@PathVariable("circuitBreakerName") String circuitBreakerName, @PathVariable("eventType") String eventType) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.getAllCircuitBreakers() .find(cb -> cb.getName().equals(circuitBreakerName)) .getOrElseThrow(() -> new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName))); Flux<CircuitBreakerEvent> eventStream = toFlux(circuitBreaker.getEventPublisher()) .filter(event -> event.getEventType() == CircuitBreakerEvent.Type.valueOf(eventType.toUpperCase())); return CircuitBreakerEventEmitter.createSseEmitter(eventStream); }
@RequestMapping(value = "stream/events", produces = MEDIA_TYPE_TEXT_EVENT_STREAM) public SseEmitter getAllCircuitBreakerEventsStream() { Seq<Flux<CircuitBreakerEvent>> eventStreams = circuitBreakerRegistry.getAllCircuitBreakers() .map(circuitBreaker -> toFlux(circuitBreaker.getEventPublisher())); return CircuitBreakerEventEmitter.createSseEmitter(Flux.merge(eventStreams)); }
@Bean public CircuitBreakerRegistry circuitBreakerRegistry(CircuitBreakerConfigurationProperties circuitBreakerProperties, EventConsumerRegistry<CircuitBreakerEvent> eventConsumerRegistry) { CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); circuitBreakerProperties.getBackends().forEach( (name, properties) -> { CircuitBreakerConfig circuitBreakerConfig = circuitBreakerProperties.createCircuitBreakerConfig(name); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(name, circuitBreakerConfig); circuitBreaker.getEventPublisher().onEvent(eventConsumerRegistry.createEventConsumer(name, properties.getEventConsumerBufferSize())); } ); return circuitBreakerRegistry; }
@Test public void shouldConsumeOnErrorEvent() { circuitBreaker.getEventPublisher() .onError(this::logEventType); circuitBreaker.onError(1000, new IOException("BAM!")); then(logger).should(times(1)).info("ERROR"); }
@Test public void shouldConsumeOnSuccessEvent() { circuitBreaker.getEventPublisher() .onSuccess(this::logEventType); circuitBreaker.onSuccess(1000); then(logger).should(times(1)).info("SUCCESS"); }
@Test public void shouldConsumeOnEvent() { circuitBreaker.getEventPublisher() .onEvent(this::logEventType); circuitBreaker.onSuccess(1000); then(logger).should(times(1)).info("SUCCESS"); }
@Test public void shouldConsumeOnResetEvent() { circuitBreaker.getEventPublisher() .onReset(this::logEventType); circuitBreaker.reset(); then(logger).should(times(1)).info("RESET"); }
@Test public void shouldConsumeOnStateTransitionEvent() { circuitBreaker = CircuitBreaker.of("test", CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(1).build()); circuitBreaker.getEventPublisher() .onStateTransition(this::logEventType); circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.onError(1000, new IOException("BAM!")); then(logger).should(times(1)).info("STATE_TRANSITION"); }
@Test public void shouldNotBufferEvents() { // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(2); assertThat(ringBuffer.getBufferedEvents()).isEmpty(); circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); //Subscription is too late circuitBreaker.getEventPublisher().onEvent(ringBuffer); //Then CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(3); //Should store 0 events, because Subscription was too late assertThat(ringBuffer.getBufferedEvents()).hasSize(0); } }
@Test public void shouldConsumeCallNotPermittedEvent() { circuitBreaker = CircuitBreaker.of("test", CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(1).build()); circuitBreaker.getEventPublisher() .onCallNotPermitted(this::logEventType); circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.isCallPermitted(); then(logger).should(times(1)).info("NOT_PERMITTED"); }
@Test public void shouldBufferErrorEvents() { // Given // tag::shouldBufferEvents[] CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(2); circuitBreaker.getEventPublisher().onEvent(ringBuffer); // end::shouldBufferEvents[] assertThat(ringBuffer.getBufferedEvents()).isEmpty(); //When circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); circuitBreaker.onError(0, new RuntimeException("Bla")); //Then CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(3); //Should only store 2 events, because capacity is 2 assertThat(ringBuffer.getBufferedEvents()).hasSize(2); //ringBuffer.getBufferedEvents().forEach(event -> LOG.info(event.toString())); }
@Test public void shouldNotProduceEventsInDisabledState() { //Given circuitBreaker = CircuitBreaker.of("test", CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(1).build()); circuitBreaker.getEventPublisher() .onEvent(this::logEventType); //When we transition to disabled circuitBreaker.transitionToDisabledState(); //And we execute other calls that should generate events circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.onError(1000, new IOException("BAM!")); circuitBreaker.isCallPermitted(); circuitBreaker.onSuccess(0); circuitBreaker.onError(1000, new IOException("BAM!")); //Then we do not produce events then(logger).should(times(1)).info("STATE_TRANSITION"); then(logger).should(times(0)).info("NOT_PERMITTED"); then(logger).should(times(0)).info("SUCCESS"); then(logger).should(times(0)).info("ERROR"); then(logger).should(times(0)).info("IGNORED_ERROR"); }
@Test public void shouldConsumeIgnoredErrorEvent() { CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .recordFailure(throwable -> Match(throwable).of( Case($(instanceOf(WebServiceException.class)), true), Case($(), false))) .build(); circuitBreaker = CircuitBreaker.of("test", circuitBreakerConfig); circuitBreaker.getEventPublisher() .onIgnoredError(this::logEventType) ; circuitBreaker.onError(1000, new IOException("BAM!")); then(logger).should(times(1)).info("IGNORED_ERROR"); }
}); SseEmitter sseEmitter = createSseEmitter(ReactorAdapter.toFlux(circuitBreaker.getEventPublisher())); TestHandler handler = new TestHandler(); sseEmitter.initialize(handler);
circuitBreaker.getEventPublisher().onEvent(cbConsumerRegistry.createEventConsumer(name, endpointsConfig.getCircuitBreakers().getEventConsumerBufferSize()));
CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig); CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(10); circuitBreaker.getEventPublisher().onEvent(ringBuffer);
if (i < TOTAL_NUMBER_CIRCUIT_BREAKERS / 2) { circuitBreaker = new CircuitBreakerStateMachine("testNameA" + i, circuitBreakerConfigGroupA); circuitBreaker.getEventPublisher().onStateTransition(eventConsumer); circuitBreakersGroupA.add(circuitBreaker); } else { circuitBreaker = new CircuitBreakerStateMachine("testNameB" + i, circuitBreakerConfigGroupB); circuitBreaker.getEventPublisher().onStateTransition(eventConsumer); circuitBreakersGroupB.add(circuitBreaker);
); chain1.get("stream/events", ctx -> { Seq<Flux<CircuitBreakerEvent>> eventStreams = circuitBreakerRegistry.getAllCircuitBreakers().map(circuitBreaker -> ReactorAdapter.toFlux(circuitBreaker.getEventPublisher())); Function<CircuitBreakerEvent, String> data = c -> Jackson.getObjectWriter(chain1.getRegistry()).writeValueAsString(CircuitBreakerEventDTOFactory.createCircuitBreakerEventDTO(c)); ServerSentEvents events = ServerSentEvents.serverSentEvents(Flux.merge(eventStreams), e -> e.id(CircuitBreakerEvent::getCircuitBreakerName).event(c -> c.getEventType().name()).data(data)); .getOrElseThrow(() -> new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName))); Function<CircuitBreakerEvent, String> data = c -> Jackson.getObjectWriter(chain1.getRegistry()).writeValueAsString(CircuitBreakerEventDTOFactory.createCircuitBreakerEventDTO(c)); ServerSentEvents events = ServerSentEvents.serverSentEvents(ReactorAdapter.toFlux(circuitBreaker.getEventPublisher()), e -> e.id(CircuitBreakerEvent::getCircuitBreakerName).event(c -> c.getEventType().name()).data(data)); ctx.render(events); }); CircuitBreaker circuitBreaker = circuitBreakerRegistry.getAllCircuitBreakers().find(cb -> cb.getName().equals(circuitBreakerName)) .getOrElseThrow(() -> new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName))); Flux<CircuitBreakerEvent> eventStream = ReactorAdapter.toFlux(circuitBreaker.getEventPublisher()) .filter(event -> event.getEventType() == CircuitBreakerEvent.Type.valueOf(eventType.toUpperCase())); Function<CircuitBreakerEvent, String> data = c -> Jackson.getObjectWriter(chain1.getRegistry()).writeValueAsString(CircuitBreakerEventDTOFactory.createCircuitBreakerEventDTO(c));