CircuitBreakerImpl implements CircuitBreaker<ET>, CircuitBreaker.ManualModeTask<ET> { protected void processSuccessfulCall() { boolean stateChanged = false; synchronized (this) { consecutiveFailureCount = 0; if (!State.CLOSED.equals(currentState)) { logger.info( "Setting circuit breaker state to CLOSED after successful call. " + "circuit_breaker_state_changed_to={}, circuit_breaker_id={}", State.CLOSED.name(), id ); currentState = State.CLOSED; ScheduledFuture<?> oldHalfOpenScheduledFuture = halfOpenScheduledFuture.getAndSet(null); if (oldHalfOpenScheduledFuture != null && !oldHalfOpenScheduledFuture.isDone()) { logger.debug( "Cancelling half-open timeout check now that the circuit is closed. circuit_breaker_id={}", id ); oldHalfOpenScheduledFuture.cancel(false); } stateChanged = true; } } if (stateChanged) { notifyOnCloseListeners(); } } CircuitBreakerImpl();  CircuitBreakerImpl(Optional<ScheduledExecutorService> scheduler,
                              Optional<ExecutorService> stateChangeNotificationExecutor,
                              Optional<Integer> maxConsecutiveFailuresAllowed,
                              Optional<Duration> resetTimeout,
                              Optional<Duration> callTimeout,
                              Optional<String> id,
                              Optional<BreakingEventStrategy<ET>> breakingEventStrategy,
                              Optional<BreakingExceptionStrategy> breakingExceptionStrategy); static Builder<E> newBuilder(); static Builder<E> newBuilder(BreakingEventStrategy<E> breakingEventStrategy); @Override ManualModeTask<ET> newManualModeTask(); @Override void throwExceptionIfCircuitBreakerIsOpen(); @Override void handleEvent(ET event); @Override void handleException(Throwable throwable); @Override CircuitBreaker<ET> originatingCircuitBreaker(); @Override CompletableFuture<ET> executeAsyncCall(Supplier<CompletableFuture<ET>> eventFutureSupplier); @Override ET executeBlockingCall(Callable<ET> eventSupplier); @Override CircuitBreakerImpl<ET> onClose(Runnable listener); @Override CircuitBreakerImpl<ET> onHalfOpen(Runnable listener); @Override CircuitBreakerImpl<ET> onOpen(Runnable listener); @Override String getId(); static final String DEFAULT_MAX_CONSECUTIVE_FAILURES_ALLOWED_SYSTEM_PROP_KEY; static final String DEFAULT_RESET_TIMEOUT_SECONDS_SYSTEM_PROP_KEY; static final int DEFAULT_MAX_CONSECUTIVE_FAILURES_ALLOWED; static final long DEFAULT_RESET_TIMEOUT_SECONDS; static final int FALLBACK_DEFAULT_MAX_CONSECUTIVE_FAILURES_ALLOWED; static final long FALLBACK_DEFAULT_RESET_TIMEOUT_SECONDS; static final BreakingEventStrategy<?> DEFAULT_BREAKING_EVENT_STRATEGY; static final BreakingExceptionStrategy DEFAULT_BREAKING_EXCEPTION_STRATEGY; }
@DataProvider(value = { "CLOSED | 0", "CLOSED | 1", "CLOSED | 9999999", "OPEN | 0", "OPEN | 1", "OPEN | 999999", }, splitBy = "\\|") @Test public void processSuccessfulCall_resets_consecutive_failure_counter_to_0_and_sets_state_to_CLOSED( State stateBeforeCall, int failureCountBeforeCall) { cbSpy.currentState = stateBeforeCall; cbSpy.consecutiveFailureCount = failureCountBeforeCall; cbSpy.processSuccessfulCall(); assertThat(cbSpy.consecutiveFailureCount).isEqualTo(0); assertThat(cbSpy.currentState).isEqualTo(State.CLOSED); }
@DataProvider(value = { "OPEN | true | false", "OPEN | true | true", "OPEN | false | false", "CLOSED | true | false", "CLOSED | true | true", "CLOSED | false | false", }, splitBy = "\\|") @Test public void processSuccessfulCall_cancels_existing_half_open_scheduled_future_if_state_changed_and_future_exists_and_future_is_not_done( State stateBeforeCall, boolean futureExists, boolean futureIsDone) { cbSpy.currentState = stateBeforeCall; ScheduledFuture futureMock = futureExists ? mock(ScheduledFuture.class) : null; cbSpy.halfOpenScheduledFuture.set(futureMock); if (futureMock != null) doReturn(futureIsDone).when(futureMock).isDone(); boolean expectStateChange = !stateBeforeCall.equals(State.CLOSED); boolean expectFutureToBeCanceled = expectStateChange && futureExists && !futureIsDone; cbSpy.processSuccessfulCall(); if (expectStateChange) assertThat(cbSpy.halfOpenScheduledFuture.get()).isNull(); else assertThat(cbSpy.halfOpenScheduledFuture.get()).isSameAs(futureMock); if (futureExists) { if (expectFutureToBeCanceled) verify(futureMock).cancel(false); else verify(futureMock, times(0)).cancel(false); } }