In Gatling, how do you make one setUp run two scenarios one after the other rather than at the same time?
answer
- side by side means at the same time
- andThen is on the population, not setUp
- children wait for the parent to terminate
- each andThen call adds another generation
- scenario names must be unique across the tree
basics
~20 sChain the second population onto the first with andThen instead of passing both as separate arguments to setUp. Populations listed side by side start together; an andThen child starts only once every user of its parent has terminated.
solid answer
~40 sPopulations passed as separate arguments to one `setUp` call all start at the same moment and run concurrently — that is the default and there is no flag to change it. Sequencing is expressed on the population itself: `parent.injectOpen(...).andThen(child.injectOpen(...))` registers the child as a dependant that Gatling will not start until **every** virtual user of the parent has terminated, not merely started. The whole tree still goes into a single `setUp` call, because the chained expression is one `PopulationBuilder`. Two details bite in practice: repeated `.andThen(...)` calls create successive generations rather than adding siblings to one, and every scenario in the tree needs a distinct name, so you cannot run literally the same `ScenarioBuilder` twice in sequence.
code
java · 22 linesimport static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
import java.time.Duration;
public class SeedThenLoadSimulation extends Simulation {
HttpProtocolBuilder httpProtocol = http.baseUrl("https://example.com");
ScenarioBuilder seed = scenario("seed").exec(http("create catalogue").post("/catalogue"));
ScenarioBuilder load = scenario("load").exec(http("list catalogue").get("/catalogue"));
{
setUp(
seed.injectOpen(atOnceUsers(1))
.andThen(load.injectOpen(rampUsers(200).during(Duration.ofMinutes(2))))
).protocols(httpProtocol);
}
}go deeper
Be able to write the andThen form for a simple two-stage run and say which population goes first and which is chained onto it.
Be ready to explain that children wait for termination rather than for injection to finish, and what the second andThen call adds.
Be ready to diagnose a run whose second stage never started, checking the parent's drain time against the run's maxDuration.
Own whether preparation work belongs in a sequential population at all, versus being provisioned outside the load test entirely.
A `setUp` call can register several populations, and the question that always follows is what "several" means for timing. The answer is that the argument list is **parallel** and `andThen` is the only thing that makes it sequential. ## The default is concurrent ```java setUp( scenario1.injectOpen(atOnceUsers(1)), scenario2.injectOpen(atOnceUsers(1)) ); ``` Both populations start when the run starts. Their injection profiles run against the same clock, their users interleave, and the report shows one set of concurrent traffic. This is what you want when you are modelling a mixed workload — browsers and checkouts hitting the same system together. ## Sequencing with andThen `andThen` is a method on `PopulationBuilder`, not on `setUp`. You call it on the population that must go first, and pass the populations that must follow: ```java setUp( seed.injectOpen(atOnceUsers(1)) .andThen(load.injectOpen(rampUsers(200).during(Duration.ofMinutes(2)))) ).protocols(httpProtocol); ``` The whole thing is still **one argument to one `setUp` call**, because `andThen` returns a `PopulationBuilder` with the children attached. The one-call rule is untouched. The trigger is **termination, not injection**. Internally each population is a node with a set of blockers; a child's blocker set is cleared only when the injector observes that the last user of the blocking population has stopped. Since the only way a virtual user terminates is by finishing its scenario, a parent whose scenario never ends is a parent whose children never start. ## Generations, and the difference two dots make This is where most mistakes live. Every call to `andThen` appends a **new generation**, so the two forms below are not the same test: | written as | what runs | |---|---| | `parent.andThen(a, b)` | `a` and `b` start together, once every `parent` user has terminated | | `parent.andThen(a).andThen(b)` | `a` starts after `parent`; `b` starts only after `a` and everything below `a` has terminated | The second form's blocker is the previous generation's **leaves**, descendants included — so if `a` itself has an `andThen` child, `b` waits for that grandchild too. Nesting works the same way in reverse: putting `.andThen(grandChild...)` *inside* one of the children makes the grandchild wait on that child alone, not on its siblings. ## The traps - **Reusing one scenario for both stages fails at startup.** Gatling flattens the whole tree and requires every scenario name to be unique, so `scn.injectOpen(...).andThen(scn.injectOpen(...))` dies with *Scenario names must be unique but found duplicates*. Build a second `ScenarioBuilder` with its own name, even if the action chain is shared. - **A `maxDuration` on `setUp` clocks the whole run, not each generation.** If the parent overruns, the children can be cut off before they ever start, and the run still stops gracefully — you get a report of a test that never ran its second half. - **The two stages report separately, up to a point.** Requests are reported under their own names, so a seeding stage's calls do not land in the load stage's per-request rows — but run-wide totals still count every request the simulation made, seeding included. - **A parent using a closed model must actually drain.** Ramping the concurrent-user count down does not interrupt users in flight; they finish their scenario first, and only then does the child unblock. ## When you actually want it The archetype is exactly the case in this question: a short preparation population that must complete before the real load begins — creating a catalogue, warming a cache, or registering the accounts the load stage will log in as. Doing that in a `before` hook is not an option, because Gatling's own SDK cannot be used inside the hooks; sequential populations are the supported way to run Gatling actions before other Gatling actions. ## Reading the tree back out of the code Because `andThen` returns the parent, a chained expression reads outside-in rather than top-down, and deeply nested trees get hard to scan. Two habits help: - Give every population a **name that says which stage it is** — `seed`, `warm-up`, `load` — because those names are what the statistics are grouped by, and they are what an error message about duplicates will quote back at you. - Extract each population into its own local variable and assemble the tree in the `setUp` call, rather than writing one expression several lines deep. `PopulationBuilder` is immutable, so a variable can be referred to once and only once in the tree without any risk of shared state — but it cannot be referred to twice, because that would duplicate its scenario name. ## Confirming it actually sequenced A sequential run is easy to assert on after the fact, because Gatling reports each population as its own scenario. If the stages overlapped, their request timelines would overlap in the report; if they sequenced correctly, the second stage's first request comes after the first stage's last one. That is worth checking the first time a preparation stage is added, because the failure mode — a seed stage that quietly ran alongside the load it was supposed to prepare for — produces a run that looks healthy and measures the wrong thing. ## What it does not give you `andThen` is a start barrier, not a data channel. Sessions belong to virtual users, so a child scenario cannot read the parent's session attributes. Anything the first stage produced has to travel through ordinary program state or an external artefact — Gatling's own documentation describes exactly this pattern, a first scenario running as a single user to fetch an auth token for the scenario that follows. Sequencing guarantees ordering and nothing more.
- Why does reusing the same ScenarioBuilder for both stages of an andThen chain fail?Because Gatling flattens the registered population tree and requires unique scenario names across all of it, children and grandchildren included. Two populations built from the same `ScenarioBuilder` share its name, so registration fails with *Scenario names must be unique but found duplicates*. Create a second builder with a distinct name; the action chain itself can be shared.
- How does andThen differ from chaining several injection steps inside one population?They answer different questions and use different triggers. Chained steps shape one scenario's arrival schedule and hand over as soon as the current step's users have **started**. `andThen` sequences whole populations and hands over only once every user of the previous one has **terminated**. Steps overlap by design; generations do not.
- Can an andThen child use a different injection model from its parent?Yes. The same-model rule applies within a single injection call, not across populations, so a parent registered with `injectOpen` can have a child registered with `injectClosed`. Gatling's own documentation example mixes them, pairing an open parent with closed children.
saying these in an interview costs you the question
- Believing populations listed in one setUp run in sequence
- Calling setUp twice to get two sequential stages
- Thinking andThen children start when the parent stops injecting
- Assuming two andThen calls add siblings to one generation