skip to content

In JMeter, how do you make a pause happen after an HTTP Request rather than before it?

level: middleimportance: must knowfreq 58%

answer

  1. The order in the thread loop is fixed
  2. Moving it down the tree only changes scope
  3. A sampler that records no result
  4. Look at the Flow Control Action element

basics

~20 s

Not by moving it. A JMeter timer always runs before the sampler in its scope. Put it on the next sampler instead, or add a Flow Control Action set to Pause with Duration 0 and make the timer its child.

solid answer

~40 s

Inside one thread iteration `JMeterThread` calls `delay(pack.getTimers())` and only then `doSampling(...)`, and the manual states the same rule: timers are processed *before* each sampler in the scope in which they are found. There is no setting that flips that. The two supported ways to get a trailing pause are to scope the timer to the **next** sampler, or to insert a **Flow Control Action** sampler with Action `Pause` after the request and make the timer its child — that element writes no sample result, so it adds the wait without polluting the JTL. Note also that a timer with no sampler in its scope is never processed at all.

code

xml · 12 lines
xml
<TestAction guiclass="TestActionGui" testclass="TestAction" testname="Flow Control Action" enabled="true">
  <intProp name="ActionProcessor.action">1</intProp>
  <intProp name="ActionProcessor.target">0</intProp>
  <stringProp name="ActionProcessor.duration">0</stringProp>
</TestAction>
<hashTree>
  <UniformRandomTimer guiclass="UniformRandomTimerGui" testclass="UniformRandomTimer" testname="Uniform Random Timer" enabled="true">
    <stringProp name="ConstantTimer.delay">300</stringProp>
    <stringProp name="RandomTimer.range">700</stringProp>
  </UniformRandomTimer>
  <hashTree/>
</hashTree>

go deeper

for a junior

Remember the direction: a timer pauses before its sampler, never after the response. Knowing that much stops the common mistake of dragging a timer under a request to delay what follows.

for a middle

Explain the loop order and the scope rule together, then give the Flow Control Action recipe with Duration 0 and a child timer, noting that the element produces no sample result.

for a senior

Bring in the reason it usually comes up: keeping a pause out of a Transaction Controller's measured elapsed time, and checking that the added element does not itself distort the results file.

for a principal

Set the house convention. Decide whether trailing pauses are expressed with Flow Control Action elements or by scoping timers onto the next sampler, so plans stay comparable and reviewable across the team.

## The order inside one iteration is fixed For each sampler, `JMeterThread.executeSamplePackage` does this, in this order: 1. configure the sample package and run the **pre-processors**; 2. call `delay(pack.getTimers())` — every timer in the sampler's scope is asked for its delay, the delays are summed, and the thread sleeps once; 3. run the sampler (`doSampling`); 4. hand the result to **post-processors**, **assertions** and **listeners**. So the sequence is *serve the timers, then sample, then process the result*. It is never *sample, wait, then serve the timers*. The user manual repeats the rule in the Timers section: "timers are processed **before** each sampler in the scope in which they are found; if there are several timers in the same scope, **all** the timers will be processed **before each** sampler." This is why the visual position of a timer in the tree is misleading. Dragging a timer *below* an HTTP Request but still inside the same controller does not make it run afterwards — it puts the timer in that controller's scope, so it runs before every sampler the controller holds. ## Two ways to get a trailing pause **Option 1 — move the pause onto the next sampler.** If the plan is `Login -> Browse -> Checkout` and you want a gap after `Login`, make the timer a child of `Browse`. The wall-clock effect is identical and the plan stays simple. The catch: it only works if there *is* a next sampler in the same iteration, and it moves with `Browse` if someone reorders the plan. **Option 2 — add a Flow Control Action sampler.** Insert a `Flow Control Action` after the request, set **Action** to `Pause` and **Duration** to `0`, then add the timer as its child. The element is a sampler for scoping purposes, so the timer fires before it; but as the manual puts it, "rather than generate a sample, the test element either pauses or stops the selected target", so no row lands in the results file. Setting Duration to `0` and using a child timer is the documented recipe for a *variable* trailing delay — the manual says "For variable delays, set the pause time to zero, and add a Timer as a child" — and it keeps the pause profile in a timer element where the rest of the plan expresses it. | Approach | Extra element | Row in the JTL | Survives reordering | |---|---|---|---| | Timer on the next sampler | none | none | no | | Flow Control Action + child timer | one sampler | none | yes | | Flow Control Action with a Duration value | one sampler | none | yes, but the pause is one parsed value | ## Why people reach for a trailing pause at all Usually it is a Transaction Controller: the parent transaction's elapsed time swallows any pause that happens before its last child, and the team wants the gap to fall outside the measured block. A Flow Control Action placed after the transaction, carrying the timer, keeps the pause out of the transaction's total. The manual calls this out directly — the sampler is useful with the Transaction Controller "as it allows pauses to be included without needing to generate a sample". ## Details worth carrying into an interview - **All timers in a scope sum.** Two timers before one sampler produce one sleep equal to the sum of their delays, not the larger of the two. - **A timer with no sampler in scope never runs.** A timer alone under a controller that contains only config elements is dead weight. - **The scheduler ends the thread rather than trimming the sleep.** When the Thread Group scheduler is on, `JMeterThread` passes the summed delay through `TimerService.adjustDelay(totalDelay, endTime, false)`. That overload never shortens: if the pause would end after the scheduled finish it returns `-1`, and `JMeterThread` sets `running = false` and returns without sleeping, so the thread simply ends. Otherwise the full pause is slept. (The Synchronizing Timer uses the other overload, which does shorten its own wait.) - **In the `.jmx` the Flow Control Action is still `TestAction`.** The element was renamed in the GUI but the saved class name did not change, so `ActionProcessor.action` set to `1` is the Pause action. ## The shape of a good answer Say plainly that JMeter has no after-the-sampler timer, name the fixed order in the thread loop, then give the Flow Control Action recipe with Duration 0 and a child timer. Mentioning that the element writes no sample result is the detail that shows you have actually built one.

  • Why set the Flow Control Action's Duration to 0 instead of typing the pause into it?
    Because a child timer is the documented way to express a variable delay, and it puts the pause profile in the same kind of element as every other pause in the plan. Duration is one string parsed with Long.parseLong at sample time; it will accept a variable or function, but the timer is where a distribution belongs. The sampler still writes no result either way.
  • Two timers sit in the same scope as one sampler. How long does the thread wait?
    For the sum. JMeterThread iterates the sampler's timers, asks each for its delay, accumulates a total and sleeps once for that total. It does not pick the largest, and it does not sleep twice.
  • Does a timer under a Thread Group run once per iteration or before every sampler?
    Before every sampler in its scope. At Thread Group level that is every sampler in the group, so a 1000 ms Constant Timer above four requests adds four seconds per iteration, not one.

saying these in an interview costs you the question

  • Says a timer placed below a sampler runs after it.
  • Claims some checkbox switches a timer to post-sampler mode.
  • Thinks a timer runs once per iteration rather than per sampler in scope.
  • Assumes the Flow Control Action writes a row into the results file.
  • Believes two timers in one scope override each other.