java.lang.Object
io.github.teceli.resiliencia.patterns.circuitbreaker.CircuitBreaker<T>
All Implemented Interfaces:
Resilient<T>

public final class CircuitBreaker<T> extends Object implements Resilient<T>
CircuitBreaker pattern: track recent call outcomes in a sliding window and stop calling a failing or slow downstream once the failure or slow-call rate crosses its threshold, rejecting calls immediately instead of piling more load onto something already struggling. Holds live state (the current CircuitState and its sliding window). Immutable in configuration and thread-safe by design — share one instance across all callers that must observe the same outcomes. Each withX method returns a new, independent CircuitBreaker, starting back in the Closed state with an empty window.
  • Method Details

    • of

      public static <T> CircuitBreaker<T> of(String name)
      A CircuitBreaker identified by name, starting Closed with the default thresholds and window size. Refine via withX methods, e.g. withFailureRateThreshold(double) to change when the circuit opens.
    • withFailureRateThreshold

      public CircuitBreaker<T> withFailureRateThreshold(double failureRateThreshold)
      Fraction of recorded calls that must fail, once the sliding window is full, to open the circuit. Must be between 0.0 (exclusive) and 1.0. Default: 0.5.
    • withSlowCallRateThreshold

      public CircuitBreaker<T> withSlowCallRateThreshold(double slowCallRateThreshold)
      Fraction of recorded calls that must exceed withSlowCallDurationThreshold(java.time.Duration), once the sliding window is full, to open the circuit. Must be between 0.0 (exclusive) and 1.0. Default: 1.0 (slow calls alone never open the circuit unless every call is slow).
    • withSlowCallDurationThreshold

      public CircuitBreaker<T> withSlowCallDurationThreshold(Duration slowCallDurationThreshold)
      What counts as a slow call. Default: no limit — no call is ever counted as slow.
    • withSlidingWindowSize

      public CircuitBreaker<T> withSlidingWindowSize(int slidingWindowSize)
      Number of most recent calls used to compute the failure and slow-call rates. Thresholds are only evaluated once this many calls have been recorded. Default: 10.
    • withWaitDurationInOpenState

      public CircuitBreaker<T> withWaitDurationInOpenState(Duration waitDurationInOpenState)
      How long the circuit stays Open before moving to HalfOpen to try test calls again. Default: 60 seconds.
    • withPermittedCallsInHalfOpenState

      public CircuitBreaker<T> withPermittedCallsInHalfOpenState(int permittedCallsInHalfOpenState)
      Number of test calls allowed through while HalfOpen. All must succeed for the circuit to close; any failure reopens it. Default: 3.
    • withRecordOn

      public CircuitBreaker<T> withRecordOn(List<Class<? extends Throwable>> recordOn)
      Exception types that count as failures. Default: any Exception. A type also listed in withIgnoreOn(java.util.List<java.lang.Class<? extends java.lang.Throwable>>) is not recorded — ignoreOn takes precedence.
    • withIgnoreOn

      public CircuitBreaker<T> withIgnoreOn(List<Class<? extends Throwable>> ignoreOn)
      Exception types that are never recorded as failures, even if also matched by withRecordOn(java.util.List<java.lang.Class<? extends java.lang.Throwable>>).
    • withRecordOnResult

      public CircuitBreaker<T> withRecordOnResult(Predicate<T> recordOnResult)
      Predicate evaluated against a successful return value to record it as a failure anyway, even though no exception was thrown — e.g. an HTTP client returning a 200 with an error body. If the predicate itself throws, that is logged as a warning and treated as false — a broken predicate never turns a successful call into a reported failure. Default: no result is ever recorded as a failure.
    • withListener

      public CircuitBreaker<T> withListener(ResilienceEvent.Listener listener)
      Add a listener notified of every CircuitBreakerEvent emitted by this instance. Listener exceptions are logged and otherwise ignored — a broken listener never affects the outcome.
    • withClock

      public CircuitBreaker<T> withClock(Clock clock)
      Use a custom Clock instead of the system clock, e.g. a manual/virtual clock in tests to make wait-duration and half-open transition assertions deterministic and instant.
    • state

      public CircuitState state()
      The current state, computed fresh on each call: for CircuitState.Open, the returned remainingWait reflects the time left until a HalfOpen test call is attempted, not the originally configured waitDurationInOpenState.

      For CircuitState.HalfOpen, permitsIssued and successes are read from two independent atomics, not under a single lock, so this is a best-effort, non-atomic snapshot: a concurrent test call can complete between the two reads, meaning the pair of values returned may never have existed together at any single instant.

    • patternKind

      public PatternKind patternKind()
      Description copied from interface: Resilient
      The kind of this pattern, used for internal comparisons (e.g. Policy order validation). Unlike Resilient.patternName(), which is a free-form observability label, this is a closed enum the library can reason about exhaustively. Defaults to PatternKind.CUSTOM for user-defined Resilient implementations.
      Specified by:
      patternKind in interface Resilient<T>
    • patternName

      public String patternName()
      Description copied from interface: Resilient
      The name of this pattern, e.g. "retry", "timeout", "circuit-breaker". Used for identification (e.g. by Policy) without coupling to concrete pattern types. Defaults to "custom" for user-defined Resilient implementations.
      Specified by:
      patternName in interface Resilient<T>
    • call

      public T call(Resilient.Operation<T> operation) throws ResilientException
      Description copied from interface: Resilient
      Execute an operation with resilience guarantees. May throw ResilienciaException or a specific pattern exception.
      Specified by:
      call in interface Resilient<T>
      Throws:
      ResilientException
    • outcome

      public Outcome<T> outcome(Resilient.Operation<T> operation)
      Description copied from interface: Resilient
      Execute an operation and capture the result or failure as an Outcome. Never throws for a recorded Exception — always returns Success, Failure, or a pattern-specific outcome. An Error thrown by the operation propagates uncaught instead of being captured as a Failure: fatal JVM conditions (e.g. OutOfMemoryError) should not be treated as a recoverable result.
      Specified by:
      outcome in interface Resilient<T>