skip to content

A Gatling Java simulation injects only constantConcurrentUsers(300).during(Duration.ofMinutes(10)) — when does that run actually stop?

level: seniorimportance: should knowfreq 37%

answer

  1. Profile duration is not run duration
  2. The run waits for the last user
  3. The tail is one scenario iteration
  4. A slow service makes the tail longer
  5. maxDuration on setUp bounds the wall clock

basics

~20 s

Not at ten minutes. When the profile's window expires Gatling stops starting replacements, but the run ends only once every user it already started has finished its scenario, so the tail is roughly one scenario iteration long.

solid answer

~40 s

The `during` value is the length of the **injection profile**, not of the run. At the end of the window the load generator marks the population fully scheduled and stops topping it up, and the simulation terminates only when every started user has completed its scenario and stopped. In a closed profile that tail is guaranteed, because 300 users are still in flight at the last tick and none is asked to stop. Its length is one scenario iteration as the system under test is performing at that moment — which is longest exactly when the service is degraded, the case where a pipeline is most likely to blow its timeout. `maxDuration` on `setUp` bounds the wall clock and stops the run gracefully, with reports and assertions still produced.

code

java · 19 lines
java
import 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 BoundedHoldSimulation extends Simulation {

  HttpProtocolBuilder httpProtocol = http.baseUrl("https://example.com");

  ScenarioBuilder scn = scenario("browse").exec(http("home").get("/"));

  {
    setUp(
      scn.injectClosed(constantConcurrentUsers(300).during(Duration.ofMinutes(10)))
    ).protocols(httpProtocol).maxDuration(Duration.ofMinutes(12));
  }
}

go deeper

for a junior

Be ready to say that the during value sizes the injection profile and the run continues until the users already started have finished.

for a middle

Be ready to explain why a closed profile always leaves a tail, and how long that tail is in terms of the scenario.

for a senior

Be ready to size a pipeline timeout from profile length plus an iteration, and to diagnose a run whose drain is far longer than expected.

for a principal

Be ready to own the trade between bounding a run's wall clock and truncating the data it was collecting, and to set that policy for a suite.

## The profile's clock and the run's clock are different clocks `constantConcurrentUsers(300).during(Duration.ofMinutes(10))` declares a **ten-minute injection profile**. It does not declare a ten-minute run. When the ten minutes elapse, the load generator stops evaluating targets and marks the population as *fully scheduled* — and then waits. The run ends only when every virtual user it has already started has finished its scenario and stopped. In a closed profile that tail is guaranteed, because the profile is defined by users that are still in flight when the clock runs out. At the last tick there are 300 of them, none of which is asked to stop. ## How long the tail is The tail is bounded by one scenario iteration, as the system under test is performing at the end of the run: - A scenario of a few HTTP calls with short pauses: seconds. - A scenario with a long loop, several pauses and a slow checkout: a minute or more. - A degraded service at the end of a stress run: the tail is exactly as bad as the response times are, which is precisely when a job is most likely to blow its timeout. That last case is the operational trap. The runs whose wall-clock length you most want to predict are the ones where the tail is longest, because the same slowness that makes the run interesting also makes its users take longer to finish. ## What the run does during the tail Everything keeps working: requests are still issued, responses are still recorded, the statistics engine is still writing. The tail is not idle time, and its measurements are part of the report — which is why a run that ends in a long, thin drain can move an aggregate figure that was computed over the whole run rather than a chosen window. ## Bounding it `maxDuration` on `setUp` is the bound: 1. It stops the whole run when the elapsed time reaches the value you give. 2. The stop reason is a **graceful** one — the run terminates in an orderly way, reports are generated and assertions are evaluated as usual. It is not a crash, and it does not by itself change the exit code. 3. It is set on `setUp`, so it applies to the simulation, not to a single population. Give it headroom over the profile's own length: a ten-minute profile bounded at ten minutes will cut the tail off every time, and everything that was still in flight is simply gone. ## Choosing the bound in a pipeline | situation | reasonable choice | |---|---| | CI job with a hard timeout | `maxDuration` a little above profile length plus one iteration | | overnight soak | no `maxDuration`; let the drain finish and keep the data | | stress run expected to degrade | `maxDuration`, because the tail grows exactly when the run hurts | | short smoke run | usually nothing; the tail is seconds | ## Diagnosing a run that will not end When a Gatling run outlives its profile by far more than one expected iteration, the question is always "what is keeping a user inside its scenario?" The usual answers: - A **loop that is still looping** — a condition that never becomes false, or a duration-bounded loop whose inner action blocks. - A **request waiting on a timeout** rather than a response, so each iteration costs the timeout. - A **retry block** turning one slow request into several. - A **pause or pacing step** longer than you remembered, multiplied by the users still holding it. The load generator's own logs record when a population finishes injecting and when its users have all stopped; the gap between those two moments is the tail, and it is the number to look at before blaming the injection profile. ## Common mistakes - Sizing a CI job's timeout from the profile's declared duration alone. - Setting `maxDuration` equal to the profile length, which silently truncates every run. - Treating a long tail as a load-generator defect rather than a property of the scenario and the service's response times. - Assuming the tail's requests are excluded from the report. They are ordinary measured requests like any other.

  • Are the requests issued during the tail included in the report?
    Yes. The tail is ordinary running time: requests are issued, responses recorded and statistics written exactly as before. That matters when an aggregate figure is computed over the whole run rather than a chosen window, because a long thin drain against a degraded service can move it.
  • What does Gatling do when maxDuration is reached?
    It stops the run for a graceful reason rather than crashing: the simulation terminates in an orderly way, reports are generated and assertions are evaluated as usual. It does not by itself change the exit code — that is still decided by whether any assertion failed.
  • A Gatling run outlives its profile by far more than one expected iteration. What do you look at?
    What is keeping a user inside its scenario: a loop whose condition never turns false, requests waiting on a timeout instead of a response, a retry block multiplying a slow call, or a pause longer than remembered. The logs record when injection finished and when the last user stopped; that gap is the tail.

A closed profile ends like a restaurant at closing time: the door stops admitting people the moment the clock says so, but the lights stay on until the last table has finished its meal.

saying these in an interview costs you the question

  • Sizing a CI timeout from the profile's declared duration alone.
  • Setting maxDuration equal to the profile length, truncating every run.
  • Blaming the injector for a long tail caused by the scenario.
  • Assuming requests issued during the drain are excluded from the report.