Live JMeter properties
MaxoPerf can set JMeter properties on a test that is already running. Anything your plan reads
through ${__P(key, default)} gets the new value on its next sample. You need no restart and no new
run, and the properties feature needs no changes to your plan.
The virtual-user and throughput controls use the same mechanism. You can also use it 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. MaxoPerf sends a live change to the runner over the control stream and applies it with
setprop("key", "value"). The property functions read from that same call.
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. Each 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 give 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 JMeter must re-evaluate on each sample, use __P directly. Do not cache it in a
User Defined Variable. JMeter evaluates UDVs once, at plan start, so they 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 |
MaxoPerf reserves the maxoperf_ namespace because it drives the virtual-user and throughput
controls through it. maxoperf_vus_target holds the thread count. maxoperf_throughput_rpm_total
holds samples per minute, the unit of JMeter’s Constant Throughput Timer field. MaxoPerf converts
it for you from the requests per second you type. (The run’s runtime file also states the per-second
number, as maxoperf_throughput_rps_total, for scripts that are not JMeter timers.) If a plan could
write those keys directly, one number would have two authorities.
MaxoPerf passes values to the engine as string literals. A value that contains quotes, semicolons or code is data, not code. Logs redact values longer than 256 characters.
Virtual users and throughput on JMeter
Section titled “Virtual users and throughput on JMeter”Both controls work live on JMeter. 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, and you can reverse it | 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 all the time, so it is the one that can follow a live change. MaxoPerf detects which thread group your plan uses when you create the run. It disables the controls that cannot work, instead of accepting a change that would do nothing.
When MaxoPerf builds the bundle, it rewrites the thread group’s target and the throughput timer’s rate to read from its own properties. You do not have to edit your plan to use the sliders. For the step-by-step version (which elements to use, and the same recipe for k6, Locust and Gatling), see Make your test controllable mid-run.