Class LoadScenarioOrchestrator
LoadSteps through a sequence of LoadStages described by a LoadProfile,
producing latency/error samples for the SLO verdict feature.
Copies the ChaosExperimentOrchestrator shape: a process-wide singleton with a
single-thread daemon ScheduledExecutorService ("load-scenario-scheduler"). The
scheduler thread does no I/O — it advances stages and computes setpoints on a fixed control
tick and hands each request to an injected sender that returns a CompletableFuture
immediately. Step pacing is scheduled (never Thread.sleep-ed), so a slow
target never blocks a worker thread.
Two load models, run in sequence:
LoadStageType.VU— closed model. The tick maintains a pool of looping virtual users sized totargetVusAt(elapsedInStage)(hold or ramp); each VU loops the steps back-to-back.LoadStageType.RATE— open model (arrival rate). The tick computes the target rater(t)in iterations/second and starts new one-shot iterations so the cumulative number started tracks the integral ofr(t)(deficit accounting), auto-scaling a VU pool up to the stagemaxVus(or the global cap). When the cap blocks the rate, the shortfall is counted as arate_limitthrottle.LoadStageType.PAUSE— drives no load; VUs drain for the duration.
Decoupling: core must not depend on the Netty HTTP client, so the actual request sender is
injected via setSender(Function) (mirrors HttpState.setReplayHandler). The Netty
runtime wires it from HttpActionHandler.getHttpClient(); unit tests pass a deterministic
synchronous fake sender to start(LoadScenario, Function).
Self-load guard: off by default (loadGenerationEnabled=false → the PUT endpoint
returns 403). Even when enabled, validate(org.mockserver.load.LoadScenario) enforces hard caps on VUs, rate, stages, duration
and step count, and dispatch is bounded live by an in-flight Semaphore and an RPS token
bucket, so a forgotten scenario cannot self-DoS the server.
Time is read via a pluggable LongSupplier clock (defaults to
TimeService.currentTimeMillis()) so tests can drive progression deterministically via
tickNow() / advanceNow(long) without wall-clock sleeps.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classImmutable snapshot of a load scenario's progress, serialized by the GET endpoint. -
Method Summary
Modifier and TypeMethodDescriptionvoidevictTerminalSeries(String name) Evict the retained metric series for a scenario removed from the registry (its run is no longer referenceable).static LoadScenarioOrchestratorStatus of the most-recently-triggered run (active or its retained terminal status), or null if none has ever run.Snapshots of every currently-active run (PENDING/RUNNING), keyed by scenario name.booleanTrue if the named scenario currently has an active (PENDING or RUNNING) run.voidreset()Reset: stop all active runs and clear all terminal status.voidsetConfiguration(Configuration configuration) Install the configuration used for caps and template engines.voidInstall the request sender that re-issues aHttpRequestto its target and returns the upstream response.start(LoadScenario scenario, Function<HttpRequest, CompletableFuture<HttpResponse>> sender) Trigger a scenario to start (run it).Status for a specific scenario name (active run snapshot or retained terminal status), or null.voidstop()Stop the most-recently-triggered run (single-run convenience).voidStop a specific scenario's active run by name.voidstopAll()Stop every active run.validate(LoadScenario scenario)
-
Method Details
-
getInstance
-
setSender
Install the request sender that re-issues aHttpRequestto its target and returns the upstream response. Called by the Netty runtime, wiring the existing HTTP client so the core never depends on it directly (mirrorsHttpState.setReplayHandler). -
setConfiguration
Install the configuration used for caps and template engines. Called by the runtime. -
start
public String start(LoadScenario scenario, Function<HttpRequest, CompletableFuture<HttpResponse>> sender) Trigger a scenario to start (run it). Returns a validation error message if the definition is invalid, the caps are exceeded, or the concurrent-scenario cap would be exceeded; ornullon success. Each trigger gets a freshrun_id. Re-triggering a name that is already active replaces that run (and evicts its prior metric series). A scenario withstartDelayMillis > 0entersPENDINGand begins after the delay; otherwise it beginsRUNNINGimmediately. Whensenderis null the installed runtime sender is used; unit tests pass a deterministic synchronous sender here. -
stop
public void stop()Stop the most-recently-triggered run (single-run convenience). Idempotent. For multi-run usestop(String)orstopAll(). -
stop
Stop a specific scenario's active run by name. Idempotent; no-op if not active. -
stopAll
public void stopAll()Stop every active run. -
reset
public void reset()Reset: stop all active runs and clear all terminal status. Called on server reset. -
getStatus
Status of the most-recently-triggered run (active or its retained terminal status), or null if none has ever run. Single-run convenience; seegetStatuses()for all runs. -
statusFor
Status for a specific scenario name (active run snapshot or retained terminal status), or null. -
isActive
True if the named scenario currently has an active (PENDING or RUNNING) run. -
getStatuses
Snapshots of every currently-active run (PENDING/RUNNING), keyed by scenario name. The registry (not the orchestrator) is the source of truth for the full scenario list; this only reports the live ones. Includes the retained terminal status for names with no active run is the caller's job viastatusFor(String). -
evictTerminalSeries
Evict the retained metric series for a scenario removed from the registry (its run is no longer referenceable). Called by HttpState when a DELETE removes a registered scenario. -
validate
-