A JMeter plan reads a property that is set only on the controller - what do the remote engines resolve it to?
answer
- The tree travels; the environment does not
- Each engine loaded its own properties at startup
- One extra RMI call carries the global set
- Check the controller's 'Sending properties' line
basics
~20 sWhatever that engine's own property set holds, which is usually nothing. Each engine evaluates the plan in its own JVM against properties it loaded at its own startup; the controller's property set does not travel with the plan.
solid answer
~50 sThe controller ships the test tree, not its environment. Elements in the plan body are precompiled and evaluated by the **engine that runs them**, so a property lookup resolves against that server's own JMeter properties - the ones its `jmeter-server` process read when it started. A value the controller holds only in memory, or that it read from its own files, is invisible there, and the lookup falls back to whatever default the function was given. Only one channel exists: after sending the tree, the controller makes a second RMI call pushing its **global** property set (the `-G` set) into each engine's properties before the run starts. JMeter adds one entry to that set for you - `sample_variables` - so the engines tag samples with the same variables the controller expects to collect. Everything else you want on a server, you put on that server.
go deeper
Remember that each JMeter server reads its own properties when it starts. Setting something on the controller does not put it on the servers, and the plan is evaluated on the servers.
Explain the two channels: properties loaded by each engine at its own startup, and a global set the controller pushes over RMI just before the run. Nothing else crosses.
Diagnose it from evidence. Read the controller's 'Sending properties' line, check the key spelling on both sides, and be suspicious of any lookup with a fallback default that could mask a missing value.
Decide where per-engine configuration lives. Per-server files make each box special and drift; pushing from the controller keeps a run reproducible from its command line. Pick one and make it a standard.
## Where the plan is actually evaluated A remote run is three RMI calls: configure with the tree, set properties, run. The tree is serialised test elements - no environment travels with it. When an engine runs that tree it precompiles it locally, exactly as a standalone run does, which means every function and variable reference in the plan body is resolved **in the engine's own JVM**. A property lookup therefore reads *that server's* JMeter properties: the ones the `jmeter-server` process loaded at startup, plus anything pushed to it since. This is the whole answer to the puzzle. Nothing is broken, and no property was "lost in transit" - it was never in transit. The controller's property set stays on the controller. ## What does travel | Set on the controller | Reaches the engines? | |---|---| | A property loaded from the controller's own property files | No | | A property set for the controller process only | No | | A JVM system property on the controller | No | | A property put in the controller's **global** set (`-G`) | Yes, pushed over RMI before the run | | `sample_variables` | Yes - JMeter copies it into the global set for you | The global push is a separate call that lands **after** the tree has been sent and **before** the run starts, so the values are in place by the time the engine precompiles. On the engine they are merged into the JVM's ordinary JMeter properties rather than being scoped to the run - they are visible to everything in that process. The engine does remember which keys arrived that way and removes them when the next property push arrives, so a stale value from run *n* does not silently survive into run *n+1*. ## Diagnosing it in ten seconds The controller logs what it pushed, verbatim, once per engine: ``` INFO o.a.j.e.ClientJMeterEngine: sent test to gen3:1099 basedir='testplans/checkout' INFO o.a.j.e.ClientJMeterEngine: Sending properties {} ``` An empty map there is the whole diagnosis: the plan expected a value and nothing was pushed. If the map is not empty and the engine still behaves as though the value is missing, the key is spelled differently in the plan than in what you pushed. ## Making a per-engine value on purpose The same rule that surprises you is also the only lever distribution gives you, because JMeter replicates the plan and offers no per-engine section in it: - **Same key, different value per server.** Because each engine reads its own properties at startup, the identical plan can behave differently on each box - a different downstream host, a different data slice, a different identity. This is the sanctioned way to differentiate replicas; the manual recommends it directly. - **Same key, one value everywhere.** Push it from the controller so all engines get it in one place and the run is reproducible from the command that started it. - **Restarting matters.** A server picks up its own property files when it starts, so editing them on a running engine changes nothing until it is restarted. Choose deliberately between those two: per-server files make each box special and drift silently; a controller push keeps the run self-describing but forces every engine to agree. ## The traps worth naming 1. **Setting the value on the controller and reading it in the plan body.** The controller is not running the plan; the engines are. 2. **Assuming a push is scoped to the run.** On the engine the pushed values join the process-wide property set for the duration. 3. **Editing a server's property file mid-campaign.** Nothing changes until that engine restarts. 4. **Letting a default hide the problem.** A property lookup with a fallback quietly returns the fallback on every engine, and the run completes looking healthy on the wrong value. 5. **Not recording what was pushed.** If the value that shaped the run lived only on one server, the result cannot be reproduced later.
- Which property does JMeter itself add to the pushed set for a distributed run, and why?`sample_variables`. The controller copies it from its own properties into the global set so every engine records the same extra variables with each sample; without it the results arriving at the controller would be missing the columns it expects to write.
- You push a property to six JMeter engines for one run. Is it gone from those engines afterwards?Not immediately. Pushed values are merged into the engine's process-wide JMeter properties and stay there; the engine records which keys came from the controller and clears exactly those when the next property push arrives with a new set. Restarting the engine also clears them.
- How would you make one JMeter plan connect to a different downstream host on each engine?Read the host from a property in the plan and give each server its own value in its own property files, which it loads at startup. The plan stays identical everywhere because the difference lives on the box, which is the only per-engine variation distribution offers.
saying these in an interview costs you the question
- Assumes the controller's property files are shipped with the plan.
- Expects a value set for the controller process to reach the engines.
- Thinks pushed properties are scoped to one run on the engine.
- Edits a running server's property file and expects it to take effect.
- Lets a function's fallback default hide a property that never arrived.