Chapter 12Lesson 04~175 minutes

Controllers: Simple, Loop, Transaction, If, While, Switch, and Throughput: Diagnostics, Failure Modes, and Production Practices

Controller defects alter workload shape before they alter latency charts. Diagnose them by comparing the expected control-flow graph with actual JTL labels and independent target request counts, then isolate generator/control state before touching server capacity.

DiagnosticsInfinite WhileDouble countingScopeControl-flow validity

Learning objectives

  • Contain and diagnose an infinite/near-infinite While loop.
  • Recognize condition-evaluation cost as generator overhead.
  • Correct a Throughput Controller mistaken for a rate controller.
  • Avoid child + transaction double counting.
  • Find timers/assertions unintentionally inherited through controller scope.
  • Simplify deep nesting without deleting business semantics or evidence.

1. Preserve first-failure evidence

All diagnostic reruns use only http://127.0.0.1:8000, ≤2 threads, and bounded duration. Preserve the failing JMX, exact branch variables/data/properties, JTL, matching jmeter.log, target event log/stats, and generator CPU/memory before editing controllers.

2. Diagnostic sequence

Controller failure diagnostic sequence

Logical controllers decide order, repetition, or inclusion. Only executed samplers create target traffic; transaction samples are reporting artifacts rather than extra HTTP requests.

flowchart TD
E[Preserve JMX + variables/data + JTL + jmeter.log + target evidence] --> V[Confirm JMeter/Java/tool versions]
V --> W[Recompute Thread Group × controller opportunities]
W --> C[Inspect If/While/Switch/Throughput state]
C --> S[Inspect Timer/Assertion/Processor scope]
S --> J[Compare JTL child/transaction labels]
J --> T[Compare independent target request counts]
T --> G[Inspect generator CPU/GC/listener cost]
G --> U[Inspect SUT telemetry/latency/errors]
U --> X[Remote/CI/container state if relevant]
X --> F[Least destructive controller correction]
F --> R[Small bounded rerun]

3. Failure mode: While condition never becomes false

Broken configuration: POLL_MORE=true is initialized but the extractor is attached to the wrong sampler, so Poll responses never update it. The While loop keeps generating Poll requests.

Bounded reproduction only: Thread Group duration 4 seconds, one thread, and a 200 ms Constant Timer under Poll. Stop if request count exceeds the predicted safety ceiling.

Evidence: repeated Poll labels, target /poll count rising, POLL_MORE unchanged. Repair the extractor scope/default and keep a hard external duration guard.

4. Failure mode: non-idempotent function in While condition

A condition such as a counter function appears to mean “loop three times,” but While evaluates its condition before and after child sampling. The counter can advance twice per cycle and behave unexpectedly.

Use Loop Controller for fixed repetition. Use While for state-driven repetition where a separate state producer sets a stable true/false value.

5. Failure mode: expensive If condition

A large JavaScript expression is evaluated for every user/iteration or every child. Target latency stays stable, but generator CPU rises and achieved RPS falls.

Repair: Interpret Condition as Variable Expression + precomputed boolean/JEXL3/Groovy when appropriate. Measure the same tiny workload before/after; do not increase heap first.

6. Failure mode: Throughput Controller used as “100 RPS”

An engineer sets Throughput=100 in percent mode and expects 100 requests/s. That simply means execute the branch on 100% of controller opportunities. Request rate still depends on threads, response time, timers, loops, and arrival model.

Repair the requirement mapping: Throughput Controller for population/branch frequency; Chapter 7 timer/workload mechanisms for request/arrival rate.

7. Failure mode: transaction and children double-counted

Additional transaction mode produces five HTTP child rows plus one Transaction row. A report sums all six as “requests.” Throughput/volume is overstated by 20% in that example.

Repair the analytics: filter transaction labels for protocol-request counts or use independent target counts. Alternatively use parent mode if the reporting pipeline is transaction-centric and accepts losing separate child CSV rows.

8. Failure mode: parent mode hides child CSV detail unexpectedly

A baseline previously saved child labels; someone enables Generate Parent Sample and the CI parser suddenly sees only transaction rows. The target behavior did not change, but result schema did.

Repair by restoring the intended Transaction mode or updating the reporting contract explicitly. Do not call missing child CSV rows a server regression.

9. Failure mode: timer inherited through controller scope

A 500 ms Constant Timer is placed under a Checkout Simple Controller above both standard and express samplers. Both branches inherit it. If only the final Submit action should include think time, the timer scope is too broad.

Walk ancestors for each sampler and list every in-scope Timer before changing latency interpretation.

10. Failure mode: assertion attached to parent transaction

In Transaction parent mode, assertions attached at the Transaction Controller can apply to both children and parent by default. A response-body assertion intended for one HTTP sampler can therefore fail unrelated samples/transaction result.

Repair with narrow sampler scope or place child samplers inside a Simple Controller and scope the assertion to that intended group.

11. Failure mode: deep nesting obscures the business transaction

A tree with Simple → If → Throughput → Loop → Switch → Transaction → Simple around one request forces reviewers to reverse-engineer five control layers. Complexity increases scope mistakes and makes sample-count math harder.

Flatten layers that do not encode business behavior. Keep one controller per real concern: repetition, branch, transaction, or intentional scope boundary.

12. Causal performance separation

Symptom Controller/generator cause Target cause to distinguish Evidence
RPS unexpectedly high extra Loop/While executions target became faster JTL label counts + target endpoint counts.
RPS unexpectedly low skipped branches, expensive condition, duration stop target slowdown controller opportunities + generator CPU + server latency.
Sample count > target requests Transaction reporting rows duplicate network traffic server event count vs JTL labels.
Transaction duration changes include timer/pre-post option changed endpoint latency change child elapsed + transaction setting + target timing.
Many assertion failures after refactor scope inheritance changed target payload regression tree ancestry + assertion labels/payload.

13. Troubleshooting shortcuts to reject

  • Do not increase thread count to compensate for a branch/loop configuration error.
  • Do not add retries or long sleeps to an infinite polling loop.
  • Do not increase JVM heap before measuring condition/listener/controller overhead.
  • Do not disable assertions/timers globally to make controller counts easier.
  • Do not disable TLS/RMI verification or move the experiment to production.
  • Do not delete the failed JTL/jmeter.log/target evidence after repair.

Knowledge check

What is the first safe response to a While loop that never exits?

Why can JavaScript If conditions reduce achieved load without changing server latency?

How do you prove Transaction rows are not extra requests?

Why can a timer appear to affect the wrong branch after controller refactoring?

What is the right repair for fixed 'loop three times' logic written as a While counter?

Next lesson

Checkpoint: predict, run, break, repair

Lesson 5 predicts one complete browse/search/poll/checkout journey, verifies JTL and target counts, then introduces a bounded controller defect and repairs it without erasing the original evidence.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was checked against current Apache JMeter primary documentation on 2026-09-05. The course baseline remains Apache JMeter 5.6.3 with a Java 17 JDK for labs and no third-party plugins; JMeter 5.6.3 requires Java 8+. Simple Controller is organizational only. Loop Controller multiplies its loop count by the enclosing Thread Group iterations and exposes an index variable named __jm__<controller-name>__idx. If Controller should normally use Interpret Condition as Variable Expression with a boolean variable or __jexl3/__groovy; JavaScript condition mode has a potentially large performance penalty. While Controller evaluates its condition before and after its children, so non-idempotent functions such as counters in the condition can produce surprising behavior. Switch Controller selects one child by numeric index or name and has explicit fallback semantics. Throughput Controller is intentionally documented as badly named: it controls branch execution count/percentage, not request throughput; use a throughput Timer for rate control. Transaction Controller creates an additional transaction SampleResult unless Generate Parent Sample is enabled. In parent mode, child samples do not appear as separate CSV JTL rows. By default transaction elapsed excludes timers and pre/post-processor processing; the optional include-duration setting changes that measurement.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.