Live JMeter properties
MaxoPerf can set JMeter properties on a test that is already running. Anything your plan reads
through ${__P(key, default)} picks the new value up on its next sample — no restart, no new run, no
changes to the plan for the properties feature itself.
This is the mechanism behind the virtual-user and throughput controls too, and it is available to you directly for your own keys.
How it works
Section titled “How it works”MaxoPerf starts JMeter with the BeanShell server listening on 127.0.0.1:9000 inside the runner
container. A live change is delivered to the runner over the control stream and applied with
setprop("key", "value"), which is exactly the call the property functions read from.
Set a property mid-run
Section titled “Set a property mid-run”-
Open the run, select the Live tab, and find the Properties editor.
-
Add or edit keys, then commit. Every commit is one revision on the run’s timeline: who, when, and which keys changed.
-
Read it in the plan with
${__P(feature.flag.checkout, v1)}. The next sample sees the new value.
From the API:
curl -X PUT "$MAXOPERF_API/v1/runs/$RUN_ID/live-controls/properties" \ -H "Authorization: Bearer $MAXOPERF_API_KEY" \ -H "X-Account-Id: $ACCOUNT_ID" \ -H 'Content-Type: application/json' \ -d '{"scope":{"type":"all"},"properties":{"feature.flag.checkout":"v2","think.time.ms":"250"}}'Use the value in your plan
Section titled “Use the value in your plan”Read properties with the built-in function, always with a default so a run started without the property still works:
<stringProp name="HTTPSampler.path">/checkout?variant=${__P(feature.flag.checkout,v1)}</stringProp>For a number that must be re-evaluated per sample, wrap it in __P directly rather than caching it
in a User Defined Variable — UDVs are evaluated once, at plan start, and will never see your change:
${__P(think.time.ms,500)}Rules for keys and values
Section titled “Rules for keys and values”| Rule | Limit |
|---|---|
| Key characters | a–z, 0–9, _, ., - — up to 64 characters |
| Keys per request | 100 |
| Value size | 4 KiB |
| Reserved namespace | maxoperf_* is rejected with 422 PROPERTY_RESERVED |
The maxoperf_ namespace is reserved because MaxoPerf drives the virtual-user and throughput
controls through it: maxoperf_vus_target (threads) and maxoperf_throughput_rpm_total — samples
per minute, the unit JMeter’s Constant Throughput Timer field is in, converted for you from the
requests per second you type. (The per-second number is also stated, as
maxoperf_throughput_rps_total, in the run’s runtime file for scripts that are not JMeter timers.)
Letting a plan write those directly would mean two authorities for one number.
Values are framed as string literals when they reach the engine, so a value containing quotes, semicolons or code is data, not code. Values longer than 256 characters are redacted in logs.
Virtual users and throughput on JMeter
Section titled “Virtual users and throughput on JMeter”Both are live on JMeter, and both have a precondition — because JMeter itself has one.
| Control | Works when | Otherwise |
|---|---|---|
| Virtual users | the plan uses a Concurrency Thread Group | disabled with jmeter.concurrency-thread-group; a PUT returns 422 CONTROL_PRECONDITION_UNMET |
| Throughput | the plan contains a Constant Throughput Timer (a Throughput Shaping Timer keeps its schedule in a table and cannot be steered) | disabled with jmeter.throughput-timer |
| Pause / resume | same as virtual users — pause is the VU target moved to 0, reversibly | disabled with jmeter.concurrency-thread-group |
Classic, Stepping and Ultimate thread groups read their thread count only when the plan loads. A Concurrency Thread Group re-reads it continuously, which is why it is the one that can follow a live change. MaxoPerf detects which one your plan uses when the run is created, and disables what cannot work rather than accepting a change that would do nothing.
MaxoPerf rewrites the thread group’s target and the throughput timer’s rate to read from its own properties when the bundle is built, so you do not have to edit your plan to use the sliders. The step-by-step version of that — which elements to use, and the same recipe for k6, Locust and Gatling — is Make your test controllable mid-run.