skip to content

Instant and Ramped Entry

The open steps that admit a fixed number of users: all at once, spread evenly across a window, or bunched into a smooth surge - plus the step that deliberately injects nobody.

on this pageshow

explore

questions

4

In Gatling's open injection model, what arrival pattern does each of nothingFor, atOnceUsers, rampUsers and stressPeakUsers produce?

level: juniorimportance: must knowfreq 70%

answer

  1. Four steps, each a fixed head-count
  2. One of them admits nobody at all
  3. Even spread versus bunched middle
  4. nothingFor, atOnceUsers, rampUsers, stressPeakUsers

basics

~20 s

nothingFor admits nobody and shifts the rest of the profile later. atOnceUsers starts a fixed count at one instant. rampUsers spreads a fixed count evenly over a window. stressPeakUsers spreads the same count bunched around that window's middle.

solid answer

~40 s

All four are **open-model injection steps** built from a fixed head-count, and all four are spelled identically in Java, Kotlin, JavaScript, TypeScript and Scala. `nothingFor(d)` injects zero users; it only pushes every later step `d` further down the timeline. `atOnceUsers(n)` schedules all `n` users at the same instant and occupies no time itself, so it does not delay what follows. `rampUsers(n).during(d)` spreads exactly `n` users evenly across `d` — first user at the start, last strictly before the end. `stressPeakUsers(n).during(d)` starts the same `n` over the same `d`, but along a smoothed Heaviside curve, so arrivals are sparse at both ends and densest in the middle. Only the last two take `.during(...)`.

code

java · 26 lines
java
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.Simulation;
import io.gatling.javaapi.http.HttpProtocolBuilder;

import java.time.Duration;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

public class FourStepsSimulation extends Simulation {

  private final HttpProtocolBuilder httpProtocol = http.baseUrl("https://example.org");

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

  {
    setUp(
      scn.injectOpen(
        nothingFor(Duration.ofSeconds(30)),
        atOnceUsers(50),
        rampUsers(200).during(Duration.ofMinutes(2)),
        stressPeakUsers(200).during(Duration.ofMinutes(2))
      ).protocols(httpProtocol)
    );
  }
}

go deeper

for a junior

Be ready to name all four steps and say in one line what each puts on the timeline, and to remember that only rampUsers and stressPeakUsers continue with .during.

for a middle

Be ready to explain that nothingFor adds time but no users while atOnceUsers adds users but no time, and to show the same profile written in both Scala and a Java-API SDK.

for a senior

Be ready to justify picking one shape over another for a real run, and to spot the quantisation and zero-argument edges before they surprise a scheduled load test.

for a principal

Be ready to argue which of these shapes a team's standard profiles should be built from, and how you keep injection profiles reviewable rather than hand-tuned per service.

## The family: a fixed head-count, declared once Gatling declares load as a **chain of injection steps** handed to one registering call. The four steps in this family share a single property: each is built from a **fixed number of virtual users**, never from a rate. You state *how many* users and *over how long*, and Gatling computes the instant at which each individual user starts. (What an open workload model is, and when you should prefer one, is performance-testing theory that belongs elsewhere; what follows is only which Gatling builder expresses which arrival shape.) All four are spelled **identically** in Java, Kotlin, JavaScript, TypeScript and Scala. What differs is the registering method — `scn.injectOpen(...)` in the SDKs that sit on the Java API (Java, Kotlin, JavaScript and TypeScript) and plain `scn.inject(...)` in Scala — and how a duration is written, which the table further down spells out. ## What each one puts on the timeline | step | argument | users added | time it occupies | takes `.during(...)` | |---|---|---|---|---| | `nothingFor(d)` | a duration | **0** | `d` | no | | `atOnceUsers(n)` | a count | `n` | **zero** | no | | `rampUsers(n).during(d)` | count, then duration | `n` | `d` | yes | | `stressPeakUsers(n).during(d)` | count, then duration | `n` | `d` | yes | - **`nothingFor(d)`** is the deliberate hole in a profile. It contributes no users whatsoever; its only effect is to push every step declared after it `d` further along the timeline. - **`atOnceUsers(n)`** schedules all `n` users at offset zero inside its own step, and occupies no time of its own. Two consecutive `atOnceUsers(10)` steps therefore give you twenty users at the same instant, not ten and then ten. - **`rampUsers(n).during(d)`** spreads exactly `n` users evenly across `d`, the first at offset zero and the last strictly *before* the end. Gatling's own unit test pins one case: five users over one second land **200 ms apart**, so the *average* spacing is `d / n`, not `d / (n - 1)`. That average is not a guaranteed interval. The window is truncated to whole seconds with `toSeconds`, the head-count is integer-sharded across those seconds and then across each second's milliseconds, so real gaps land on `d / n` only when the count divides cleanly: `rampUsers(3).during(8)` starts its three users at 0 s, 2 s and 5 s — gaps of 2 s and 3 s, not the 2.67 s the formula suggests. - **`stressPeakUsers(n).during(d)`** injects the same `n` users over the same `d`, but places them along a smooth approximation of the Heaviside step function. Arrivals are sparse at both ends and densest in the middle. In Gatling's own test for 100 users over 5 seconds, **67 of them** land in the middle two seconds; an evenly spread ramp would put about 40 there. ## Writing them in each SDK | language | registering call | how a duration is written | |---|---|---| | Java | `injectOpen` | `rampUsers(200).during(Duration.ofMinutes(2))` | | Kotlin | `injectOpen` | `rampUsers(200).during(Duration.ofMinutes(2))` | | JavaScript / TypeScript | `injectOpen` | `rampUsers(200).during({ amount: 2, unit: "minutes" })` | | Scala | `inject` | `rampUsers(200).during(2.minutes)` | A **bare number is a count of seconds**. In Java and Kotlin that is an explicit overload — `during(long durationSeconds)` and `nothingFor(long durationSeconds)`. In Scala it is an implicit conversion in `io.gatling.core.Predef` that turns an `Int` into that many seconds. So `rampUsers(10).during(5)` means five seconds in every SDK. ## What the counts guarantee Because every step in this family carries a fixed count, the profile's totals are simple sums: 1. The **total number of users** a population starts is the sum of the steps' counts, with every `nothingFor` contributing zero. 2. The **length of the injection profile** is the sum of the steps' durations, with every `atOnceUsers` contributing zero. 3. Neither total says anything about when the run *ends* — users still have to finish the scenario they were started into. ## Degenerate arguments Gatling folds away The implementations collapse the boring cases rather than failing on them: - `rampUsers(n).during(0)` behaves exactly like `atOnceUsers(n)`. - `rampUsers(0).during(d)` behaves exactly like `nothingFor(d)`; the window is still consumed. - `stressPeakUsers(n).during(0)` likewise degrades to `atOnceUsers(n)`, and `stressPeakUsers(0).during(d)` to `nothingFor(d)`. - A negative count or a negative duration trips a `require` check and aborts the run before any user starts. One rougher edge: the ramp distributes users **per whole second**, because the window is truncated with `toSeconds`. A ramp window shorter than one second consequently starts nobody at all, while still delaying whatever follows it. ## What is deliberately not in this family `constantUsersPerSec` and `rampUsersPerSec` look similar but are **rate-based**: you supply users per second plus a duration and the head-count falls out of the arithmetic. `constantConcurrentUsers` and `rampConcurrentUsers` are closed-model steps that hold a number of users *inside* the system instead of declaring arrivals. Every step passed to one registering call must be of the same model kind, so a count-based open step cannot share a call with a concurrent-users step.

  • Which of these four steps accept a chained .during(...) call, and which are already complete?
    Only `rampUsers(n)` and `stressPeakUsers(n)` return a builder that needs `.during(d)`. `atOnceUsers(n)` and `nothingFor(d)` return a finished injection step, so `atOnceUsers(500).during(10)` does not compile. `nothingFor` already carries its duration as its single argument.
  • In Gatling's Java DSL, what duration does the bare number in nothingFor(120) mean?
    Seconds — two minutes. `CoreDsl` declares an overload `nothingFor(long durationSeconds)` alongside `nothingFor(Duration)`. Scala reaches the same result through an implicit `Int`-to-seconds conversion in `io.gatling.core.Predef`. Passing a `java.time.Duration` explicitly avoids confusing `nothingFor(2)` with two minutes.
  • What does rampUsers(0).during(30) actually do?
    Exactly what `nothingFor(30)` does: it starts no users but still consumes thirty seconds of the profile, delaying every step declared after it. Gatling folds the zero-count case into the do-nothing step rather than rejecting it, and the same folding applies to `stressPeakUsers(0).during(d)`.

saying these in an interview costs you the question

  • Thinking atOnceUsers takes a .during window like rampUsers does
  • Believing nothingFor waits for already-started users to finish
  • Assuming stressPeakUsers starts more users than an equivalent rampUsers step
  • Expecting different step names in Scala than in Java or JavaScript
open as a page

In a Gatling simulation, how do you declare two minutes in which nobody arrives followed by 500 virtual users starting at the same instant?

level: middleimportance: must knowfreq 52%

basics

~20 s

Chain two open injection steps in one call: nothingFor for the two-minute gap, then atOnceUsers(500). The gap adds no users and only delays what follows; the surge places all 500 users on one instant and costs no time.

open as a page

In Gatling, rampUsers(1000).during(60) and stressPeakUsers(1000).during(60) both start 1000 users over 60 seconds — what actually differs?

level: middleimportance: should knowfreq 42%

basics

~20 s

Only the arrival shape. Both start exactly 1000 users and both occupy 60 seconds. The ramp spaces arrivals evenly; the stress peak follows a smoothed Heaviside curve, so arrivals are sparse at both ends and densest in the middle.

open as a page

A Gatling simulation calling heavisideUsers(1000).during(20) stopped compiling after an upgrade — what happened to that injection step?

level: seniorimportance: should knowfreq 30%

basics

~10 s

It was renamed. heavisideUsers became stressPeakUsers in Gatling 3.7, kept only as a deprecated alias, and that alias was dropped in 3.11. Substituting stressPeakUsers is the whole fix; the arrival shape is unchanged.

open as a page