Class ForwardCircuitBreaker

java.lang.Object
org.mockserver.mock.action.http.ForwardCircuitBreaker

public class ForwardCircuitBreaker extends Object
Per-upstream circuit breaker for forwarded/proxied requests. State is keyed by upstream host:port. After forwardProxyCircuitBreakerFailureThreshold consecutive failures to one upstream the breaker trips open and #allowRequest(String) fails subsequent requests fast (the caller returns a 503) for forwardProxyCircuitBreakerWindowMillis. Once the window elapses the breaker moves to half-open: it permits a single trial request. A success (#recordSuccess(String)) closes the breaker; a failure (#recordFailure(String)) re-opens it for another window.

The whole mechanism is inert unless forwardProxyCircuitBreakerEnabled is true, so the default behaviour (every request attempted) is unchanged.

The singleton instance is shared process-wide, consistent with ChaosAutoHaltMonitor and LlmCostBudgetMonitor. The number of currently-open upstreams is exposed via openCircuitCount() (and the mock_server_upstream_circuit_open Prometheus gauge).

  • Method Details

    • getInstance

      public static ForwardCircuitBreaker getInstance()
    • keyFor

      public static String keyFor(InetSocketAddress remoteAddress)
      Build the stable per-upstream key from a resolved socket address (host and port only — never the path), returning null when no usable host is available.
    • allowRequest

      public boolean allowRequest(Configuration configuration, String key)
      Decide whether a request to the given upstream may proceed.
      • Closed — always allowed.
      • Open and still within the window — rejected (fail fast).
      • Open but the window has elapsed (half-open) — exactly one trial request is allowed through; concurrent callers in the same window are rejected.
      Parameters:
      key - the upstream key from keyFor(InetSocketAddress) (a null/blank key always allows)
      Returns:
      true if the request should be forwarded, false to fail fast with a 503
    • recordSuccess

      public void recordSuccess(Configuration configuration, String key)
      Record a successful forward to the given upstream. Closes the breaker and clears the failure count. No-op when the breaker is disabled or the key is null.

      A fully-healthy upstream (closed, zero failures, no trial in flight) is evicted from the per-upstream map so a steadily-succeeding upstream leaves no permanent footprint. This bounds the map to currently-degraded upstreams and closes the only growth vector — distinct keys (e.g. via varied client Host headers when no explicit remote address is supplied). Eviction is value-conditional (ConcurrentHashMap.remove(Object, Object)) so a state whose map entry has been replaced is never dropped, and is guarded on the state still being fully healthy. The only thing a concurrent recordFailure(org.mockserver.configuration.Configuration, java.lang.String) can lose to this is an in-place sub-threshold failure increment on a still-closed breaker, which is benign: the breaker counts consecutive failures since the last success, so a success legitimately resets that count. An entry that a concurrent failure trips open is retained (the health re-check sees openedAtMillis != 0).

    • recordFailure

      public void recordFailure(Configuration configuration, String key)
      Record a failed forward to the given upstream. Increments the consecutive-failure count and trips the breaker open once the configured threshold is reached (or immediately re-opens it on a failed half-open trial). No-op when the breaker is disabled or the key is null.
    • openCircuitCount

      public int openCircuitCount()
      Number of upstreams whose breaker is currently open (in the open or half-open state). Backs the mock_server_upstream_circuit_open gauge. Counts an upstream as open whenever its open timestamp is non-zero, regardless of whether the window has elapsed, so the gauge reflects "this upstream is currently degraded" until a trial request closes it.
    • isOpen

      public boolean isOpen(String key)
      True when the breaker for the given key is currently open (open timestamp set). Test/diagnostic helper.
    • reset

      public void reset()
      Reset all per-upstream state. Called on server reset and for test isolation.