skip to content

Loops and Guard Blocks

The blocks that wrap part of a chain: loops carrying a session counter, conditional and weighted switches, and guards that retry, exit or stop the run. Interviewers probe the failure ones.

on this pageshow

explore

questions

6

In a Gatling scenario, how do you repeat a chain a fixed number of times or for a fixed duration, and how do the Java and Scala spellings of those loops differ?

level: juniorimportance: must knowfreq 70%

answer

  1. Two bounds: a count and a clock
  2. One counts iterations, one watches elapsed time
  3. repeat(times) and during(duration)
  4. Java attaches the body with .on
  5. Counter starts at 0, name it yourself

basics

~10 s

repeat(n) runs the wrapped chain n times; during(d) runs it until d has elapsed. Java, Kotlin and JavaScript attach the body with .on(...), while Scala passes it in a second parameter list.

solid answer

~40 s

Gatling's count-bounded loop is `repeat(times)` and its time-bounded loop is `during(duration)`. `times` can be a literal integer, a Gatling EL string resolving to an integer, or a function of the session. `duration` can be a bare number meaning seconds, a `java.time.Duration` in Java and Kotlin, a Scala duration literal, or an object such as `{ amount: 10, unit: "minutes" }` in JavaScript and TypeScript. The body attaches differently per SDK: Java, Kotlin, JavaScript and TypeScript write `repeat(5).on(chain)`, while Scala writes `repeat(5)(chain)`. Both blocks keep an iteration counter in the session starting at 0 under a generated private name; pass a second argument such as `repeat(5, "counter")` to name it yourself, and treat that attribute as read-only.

code

java · 10 lines
java
ScenarioBuilder scn = scenario("browse")
  .repeat(5).on(
    http("home").get("/")
  )
  .during(Duration.ofMinutes(2)).on(
    http("search").get("/search")
  )
  .repeat(5, "attempt").on(
    http("home").get("/")
  );

go deeper

for a junior

Be ready to write both loops from memory in your own SDK, and to say that during takes a duration while repeat takes a count.

for a middle

Explain that the body attaches with .on in the Java-API languages and with a second parameter list in Scala, and that the counter starts at 0.

for a senior

Show judgment about which bound belongs in the scenario at all: a per-user iteration count is scenario shape, and a run-long duration usually belongs to the injection profile instead.

for a principal

Own the convention across a suite: whether loops carry named counters, how nested loops are kept distinct, and how to keep one scenario readable in the SDK your team actually writes.

## The two everyday loops A Gatling **scenario** is a chain of actions, and a *loop block* wraps part of that chain so a virtual user walks it more than once. Two blocks carry almost all of that traffic: - **`repeat(times)`** — a count-bounded loop. The body runs exactly `times` times. - **`during(duration)`** — a time-bounded loop. The body restarts for as long as the time elapsed since the user entered the block is within `duration`. `times` accepts a literal integer, a Gatling Expression Language string that resolves to an integer, or a function of the session — so the number of iterations can differ per virtual user. `duration` accepts more forms, and that is where the SDKs genuinely diverge. ## A duration is spelled four ways | SDK | how you write ten minutes | |---|---| | Java, Kotlin | `Duration.ofMinutes(10)` — a `java.time.Duration` | | Scala | `10.minutes` — a `scala.concurrent.duration` literal | | JavaScript, TypeScript | `{ amount: 10, unit: "minutes" }` — an object literal | | all of them | a bare number, meaning **seconds**: `during(5)` | `during` also takes a Gatling EL string or a function returning a duration. The bare-number form is the one that trips people: `during(5)` is five **seconds**, not five iterations and not five minutes. ## Attaching the body: `.on(...)` versus a second parameter list The loop names are identical across the SDKs; the way you hang the body off them is not. - **Java, Kotlin, JavaScript and TypeScript** use a two-part call: `repeat(5).on(chain)` and `during(Duration.ofMinutes(2)).on(chain)`. The `.on(...)` method takes one or more executables, and they run **sequentially** inside each iteration. - **Scala** puts the body in a second parameter list: `repeat(5)(chain)` and `during(2.minutes)(chain)`. This is the same split that runs through the whole DSL, and it is worth saying out loud in an interview: writing `repeat(5)(...)` in Java does not compile, and writing `repeat(5).on(...)` in Scala does not either. Kotlin, JavaScript and TypeScript follow the Java shape because they sit on the Java API rather than on the Scala core. ## The loop counter Every loop block keeps an iteration counter for the virtual user, and it **starts at 0**. By default Gatling generates a private, unstable attribute name for it, which is deliberate — you are not supposed to depend on it. Pass a second argument to name it yourself: ```java repeat(5, "attempt").on( http("home").get("/") ); ``` Two facts about that counter matter in practice: 1. Gatling's own reference warns that a counter you have named must be treated as **read-only**. It is part of the loop's internal bookkeeping; writing to it breaks the block. 2. The counter exists only inside the block. When the loop finishes, Gatling removes the attribute from the session, so the name is not readable afterwards. ## The rest of the loop family `repeat` and `during` are two of eight loop blocks. The others fill the gaps: - **`forever()`** — no bound at all; you are relying on something outside the block to end the user. - **`foreach(list, "elt")`** — one iteration per element of a sequence, exposing the current element under the attribute name you give as the second argument. The sequence can be a literal list, an EL string, or a function. - **`asLongAs(condition)`** and **`doWhile(condition)`** — condition-driven loops, differing in whether the condition is read before or after the body. - **`asLongAsDuring(condition, duration)`** and **`doWhileDuring(condition, duration)`** — condition plus a clock bound. ## What people get wrong - **Reading `during(5)` as a count.** It is a duration in seconds. `repeat(5)` is the count. - **Expecting `during(60)` to stop at exactly 60 seconds.** It stops when it next checks; a long iteration can overrun unless the block's `exitASAP` argument is on, and even then the exit happens at an action boundary. - **Mixing the SDK spellings.** `Duration.ofMinutes(10)` inside a JavaScript simulation is not a duration Gatling understands; that SDK wants `{ amount: 10, unit: "minutes" }`. - **Assuming the counter starts at 1.** It starts at 0, so the last value inside `repeat(5)` is 4. - **Nesting loops without naming their counters.** Two nested loops each get their own generated counter, which is fine — but if you want to tell them apart you must name both.

  • What does Gatling's foreach block give you that repeat does not?
    `foreach(sequence, "elt")` runs one iteration per element and binds the current element to the attribute name you supply, so the body can use the value rather than just an index. The sequence can be a literal list, a Gatling EL string, or a function of the session.
  • What happens to a named loop counter once the loop finishes?
    Gatling removes it. The counter attribute exists only while the virtual user is inside the block, so it cannot be read after the loop ends. Gatling's reference also warns that while the loop is running the attribute must be treated as read-only, because the block's own bookkeeping uses it.
  • Why does Gatling generate a private counter name when you do not supply one?
    So that nested and repeated loops never collide, and so that nothing in your scenario grows a dependency on an internal attribute. Supplying `counterName` is an opt-in: you are declaring that you intend to use the value, and taking on the responsibility of not writing to it.

saying these in an interview costs you the question

  • Reading during(5) as five iterations rather than five seconds
  • Writing repeat(5)(chain) in Java, where the body needs .on(...)
  • Assuming the loop counter starts at 1
  • Using Duration.ofMinutes in a JavaScript simulation instead of an object literal
  • Writing to a named loop counter instead of only reading it
open as a page

In a Gatling scenario, a token-refresh request intermittently returns 401 — how do you retry just that step, and what do the failed attempts do to the run's request statistics?

level: seniorimportance: must knowfreq 52%

basics

~20 s

Wrap the refresh step in tryMax(n): any failure inside restarts the wrapped chain, up to n attempts in total. Every attempt is recorded, so the failed ones still appear as KO requests in the run's statistics.

open as a page

In a Gatling scenario, how do doIf, doSwitch and randomSwitch each choose which chain to run, and what happens when none of them matches?

level: middleimportance: should knowfreq 48%

basics

~20 s

doIf runs its chain when a boolean condition holds, doSwitch matches a resolved key against case keys, and randomSwitch draws by percentage weight. When nothing matches the block is skipped, unless an OrElse variant supplies a fallback.

open as a page

In Gatling's scenario DSL, how does asLongAs differ from doWhile, and what do asLongAsDuring and doWhileDuring add?

level: middleimportance: should knowfreq 45%

basics

~20 s

asLongAs tests its condition before each iteration, so the body can run zero times; doWhile tests it after, so the body always runs at least once. The During variants add a maximum duration that also ends the loop.

open as a page

In a Gatling simulation, how would you decide between retrying a failing step, dropping the affected virtual user, and stopping the whole run?

level: principalimportance: should knowfreq 38%

basics

~20 s

Match the block to the blast radius: tryMax retries one chain, exitHereIfFailed ends that virtual user's scenario, and stopLoadGenerator ends the run for everyone. Retry transient faults, drop users whose remaining work is meaningless, stop only when the run is void.

open as a page

In a Gatling loop such as during or asLongAs, what does the exitASAP argument change about when the loop stops?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

With exitASAP on, Gatling re-checks the loop condition before every action in the body, so a virtual user can leave part-way through an iteration. With it off, the iteration already in flight always finishes first.

open as a page