Class PreemptionSimulator

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

public class PreemptionSimulator extends Object
Process-wide state machine for a simulated server preemption (node drain / Spot reclamation / pre-SIGTERM): when start(PreemptionRequest) is called the server becomes cordoned — new data-plane exchanges are turned away (503 + Connection: close on HTTP/1.1, GOAWAY on HTTP/2, per PreemptionRequest.Mode) while in-flight requests are allowed to drain for a bounded window. It is a simulation only: it never calls stop() / stopAsync() and never tears down the event loops. The cordon clears on an explicit uncordon() or automatically after ttlMillis (a dead-man's switch so a forgotten simulation self-heals).

The design mirrors ServiceChaosRegistry's singleton + controllable-clock + TTL pattern, but is server-scoped (a single cordon, no host keying). It holds no Netty references: the in-flight count is read through an injected IntSupplier (wired from LifeCycle.getRequestsInFlight()), keeping mockserver-core free of a netty dependency. GOAWAY emission is performed lazily on the netty side when an HTTP/2 client hits a cordoned connection (see HttpRequestHandler); this class is the authoritative cordon state.

State is cleared on server reset (see HttpState.reset()).

  • Constructor Details

    • PreemptionSimulator

      public PreemptionSimulator(LongSupplier clock)
  • Method Details

    • getInstance

      public static PreemptionSimulator getInstance()
    • setInFlightSupplier

      public void setInFlightSupplier(IntSupplier inFlightSupplier)
      Wire the supplier used to read the current in-flight data-plane request count (from LifeCycle.getRequestsInFlight()). Null is ignored.
    • start

      Begin (or replace) a preemption simulation. The drainMillis and ttlMillis are each clamped to preemptionSimulationMaxDrainMillis. When drainMillis is null it defaults to stopDrainMillis (the same drain budget a real graceful shutdown uses). When mode is null it defaults to PreemptionRequest.Mode.both.
      Returns:
      the effective request actually applied (with defaults and clamping resolved)
    • start

      public PreemptionRequest start(Configuration configuration, PreemptionRequest req)
      As start(PreemptionRequest), but resolves preemptionSimulationMaxDrainMillis from the supplied Configuration instance when one is given, falling back to the static ConfigurationProperties store otherwise. The instance is preferred so a cap set programmatically or via PUT /mockserver/configuration actually clamps the drain/TTL; the static fallback keeps system-property/env/file users unaffected.
      Parameters:
      configuration - the server configuration, may be null
      Returns:
      the effective request actually applied (with defaults and clamping resolved)
    • isCordoned

      public boolean isCordoned()
      Whether the server is currently cordoned. Auto-uncordons (lazily, here) once the TTL has elapsed, so a forgotten simulation self-heals without an explicit uncordon.
    • inFlight

      public int inFlight()
      The current in-flight data-plane request count, via the wired supplier.
    • getRequest

      public PreemptionRequest getRequest()
      The active preemption request (effective, post-clamp), or null when not cordoned.
    • getMode

      public PreemptionRequest.Mode getMode()
      The active mode, or null when not cordoned.
    • rejectsNewExchanges

      public boolean rejectsNewExchanges()
      true when the active simulation rejects new data-plane exchanges with a 503 (modes reject503 and both). When the mode is goaway only, new exchanges are not rejected with a 503 — the HTTP/2 GOAWAY alone signals clients to drain — so this returns false. Returns false when not cordoned.
    • emitsGoAway

      public boolean emitsGoAway()
      true when the active simulation signals HTTP/2 clients to drain via a GOAWAY frame (modes goaway and both). Returns false when not cordoned. Read by the netty runtime to decide whether to emit a lazy GOAWAY on a cordoned HTTP/2 connection. Thread-safe: reads the active request through the same path as isCordoned().
    • goAwayLastStreamId

      public long goAwayLastStreamId()
      The lastStreamId to advertise on a preemption GOAWAY, or -1 when not cordoned or unset (-1 tells Http2GoAwayEmitter to use the connection's current last stream).
    • drainRemainingMillis

      public long drainRemainingMillis()
      Milliseconds remaining in the drain window (until drainDeadlineMillis), floored at 0. Returns 0 when not cordoned. This reflects the drain budget, not the TTL.
    • drainDeadlinePassed

      public boolean drainDeadlinePassed()
      true once the drain window has elapsed while still cordoned (stragglers may remain).
    • state

      public String state()
      A human-readable state string for the status endpoint: "inactive" when not cordoned, "draining" while within the drain window, or "drained" once the drain deadline has passed (the server stays cordoned until TTL/uncordon).
    • uncordon

      public void uncordon()
      Clear the cordon explicitly (idempotent).
    • reset

      public void reset()
      Reset all state. Called on server reset and for test isolation. Does not clear the wired supplier.