Change virtual users mid-run
You can change a test while it runs. On the run’s Live tab you move the virtual user target and the throughput cap while the load is in flight, and you pause and resume it. The run’s timeline records every change, with who made it and when.
Nothing restarts. The run keeps its id, its result series and its report.
Before you start
Section titled “Before you start”- The run must be running. A queued or finished run answers
409 RUN_NOT_RUNNING. - You need the controller role on the run (account members and test editors have it).
- Your executor and your script must support the control. JMeter, k6, Locust and Gatling can move
virtual users live. The other executors cannot, and the console says so.
On every engine except Locust, the script also has to be built for it: a Concurrency Thread Group on JMeter, an
externally-controlledscenario on k6, the helper opt-in on Gatling. Make your test controllable mid-run has the recipe per engine. What each executor supports at runtime has the full matrix.
Change the virtual user target
Section titled “Change the virtual user target”-
Open the run and select the Live tab.
-
Set the Virtual users field to the new fleet-wide total and commit it.
The number you type is always the whole fleet. Under the field, MaxoPerf shows how it will divide that number, for example
2 000 = 20 runners × 100. You always see what each runner is told. -
Watch the ack pill. It counts the runners that have confirmed the change:
applied 4 987 / 5 000. It normally converges in well under a second. -
Check that the change reached the load. The run’s charts get a vertical marker at the moment the change applied, so a step in the VU or throughput series lines up with the change that caused it.
Change the throughput cap
Section titled “Change the throughput cap”The flow is the same, with the Requests per second field. 0 means unlimited.
Pause and resume
Section titled “Pause and resume”The Pause toggle stops the load without ending the run. Use it to fail something over, take a snapshot, or let a queue drain, then continue in the same run and the same charts. Resume restores the previous target.
Scope a change to part of the fleet
Section titled “Scope a change to part of the fleet”By default a change applies to every live runner. The scope chips narrow it:
| Scope | Use it for |
|---|---|
| All | the whole fleet (default) |
| Locations | one cloud region, or one private datacenter |
| Runners | named individual runners |
If a scope resolves to zero live runners, MaxoPerf rejects it with 422 SELECTOR_NO_MATCHING_RUNNERS.
It never accepts the change and then quietly applies it to nothing.
Plan limits
Section titled “Plan limits”Your plan’s maxLiveConcurrentVus and maxLiveThroughputRps cap increases. An increase past
them returns 403 PLAN_LIMIT_EXCEEDED. Enterprise sets both to -1 (unlimited), so that plan
never refuses a mid-run increase.
Decreases are never blocked, even on a run that started above the cap. If your test is overloading the system under test, you can always turn it down.
From the API
Section titled “From the API”curl -X PUT "$MAXOPERF_API/v1/runs/$RUN_ID/live-controls/virtual-users" \ -H "Authorization: Bearer $MAXOPERF_API_KEY" \ -H "X-Account-Id: $ACCOUNT_ID" \ -H 'Content-Type: application/json' \ -d '{"scope":{"type":"all"},"total":2000}'// 202 Accepted{ "revision": 7, "perRunner": 100, "runnerCount": 20, "dispatchState": "dispatched", "delivered": true }MaxoPerf rounds the per-runner share up and never below 1, so a small total across a wide fleet cannot be delivered exactly. When that happens, the response says so, and the timeline shows the total as approximate:
// 202 Accepted — 7 RPS across 20 runners is 1 each, so the fleet will really run 20{ "revision": 8, "perRunner": 1, "runnerCount": 20, "clamped": true, "effectiveTotal": 20, … }clamped is absent whenever the divide is exact. If a decrease comes back clamped, the fleet is
too wide for the target. Release runners, or accept effectiveTotal as the floor.
To read the outcome back, use GET /v1/runs/:runId/live-controls for the desired state,
capabilities and ack tallies. Use GET /v1/runs/:runId/live-controls/history for the full change log.
Use GET /v1/runs/:runId/live-controls/revisions/:revision/acks?status=failed for the exact runners
that have not applied a revision.