A Gatling run stopped eight minutes into a planned thirty with 'Feeder csv(credentials.csv) crashed: feeder is now empty' — what outputs does that run leave you, and how do you size the file so the next one finishes?
answer
- the run has no verdict at all
- the raw log survives, the report does not
- count feed executions, not virtual users
- growing the file is the only uniqueness-preserving fix
basics
~20 sThat run leaves its raw log but no HTML report and no assertion verdict, because a crash stops it first. Size the file from feed step executions - arrival rate times duration times feeds per user - and add headroom.
solid answer
~40 sThat feeder is on the default `queue` strategy, so its rows are consumed once each and the first `feed` call to find it empty stops the load generator. What survives is the raw per-run log covering the eight minutes; there is no HTML report and no assertion result, because the crash propagates before Gatling evaluates anything — you can rebuild the report from the log with `--reports-only` to see whether the part that ran was healthy. For the next run, size the file from **feed step executions**, not users: arrival rate times duration times feeds per user, with a loop multiplying it. Growing the file is the only fix that preserves uniqueness; moving to `circular` removes the crash but puts two virtual users behind one credential.
code
java · 7 lines// 20 users/sec for 30 min = 36,000 users.
// The scenario feeds once per user, so the file needs >= 36,000 rows.
setUp(
login.injectOpen(
constantUsersPerSec(20).during(Duration.ofMinutes(30))
)
).protocols(httpProtocol);go deeper
Be ready to say that the message names the exhausted feeder and that the default strategy does not recycle, so the file simply held fewer rows than the run needed.
Explain the arithmetic that sizes the stock and why a feed inside a loop multiplies it, and say which artefacts a crashed run leaves behind.
Show the judgment: decide from what the records represent whether reuse is even permissible, add headroom deliberately, and make sure a crashed run cannot be read as a pass.
Own the provisioning story across environments — who supplies identities at the volume a soak needs, and what the suite does when that volume cannot be met.
## Read the message first The line names the feeder and, on the JVM SDKs, the source position of the `feed(...)` step that drew from it: ``` Feeder csv(credentials.csv) (defined at: LoginSimulation.<init>(LoginSimulation.java:28)) crashed: feeder is now empty. ``` That tells you which of the simulation's feeders ran dry — useful the moment there is more than one — and which `feed` step ran it dry. Read the position for what it is: the line that called `feed(...)`, captured while the DSL was building that step, **not** the line that declared the builder. On the usual layout — `FeederBuilder<String> credentials = csv("credentials.csv")` once, `.feed(credentials)` somewhere below — those are two different lines, and they coincide only when the builder is written inline inside the `feed(...)` call. The feeder in question is on the default **`queue`** strategy: every record goes out at most once, and the first `feed` call that finds the iterator empty stops the load generator. ## What the run left behind | artefact | present after a feeder crash? | |---|---| | raw per-run simulation log | yes, covering the eight minutes that ran | | HTML report | **no** — the run never reached report generation | | assertion results | **no** — assertions are evaluated after a completed run | | `after` hook side effects | yes, the hook still executed | | KO entries explaining the stop | no, nothing failed as a request | So the run has **no verdict**. That is the trap for a CI job: there is no failed assertion to catch, because assertions never ran. The failure surfaces as a crashed process, and a gate that only reads assertion output will report nothing rather than reporting red. The eight minutes of data are not lost, though — the raw log is on disk, and Gatling's `--reports-only` option will build the HTML report from it after the fact, which is usually the fastest way to see whether the part that did run was healthy before the data ran out. ## Size the file from the profile, not from the user count The stock is consumed once per **`feed` step execution**, so the arithmetic is: ``` records needed = (users started over the run) x (feed executions per user) ``` - In an **open** model, users started is the arrival rate integrated over the run — 20 users/sec for 30 minutes is 36,000 users, whatever the concurrency chart shows. - In a **closed** model you cannot read it off the profile at all: how many users complete a scenario in 30 minutes depends on how fast the target responds, so size against your worst-case (fastest) expectation, not your average. - A `feed` inside a loop multiplies by the loop count. Two `feed` steps in one scenario double it. - Two separately declared feeders over the *same* file do not share a cursor: each reads the file from the top, so the same credentials go out twice and your effective stock is not what you think it is. Declare the builder once and reuse that value. Then add headroom. A run sized to exactly the expected draw crashes on the first retry, the first ramp overshoot, or the first time someone lengthens the soak. ## Deciding what to change Growing the file is the only fix that preserves the property `queue` was chosen for. Before reaching for `circular` to make the problem go away, check what the records actually are: - **Identity-bearing records** — logins, single-use tokens, accounts a test mutates. Keep a consuming strategy and grow the stock, or shorten the run. Reusing these puts two virtual users behind one identity, and the target's own serialisation, token invalidation or duplicate-login rejection then shows up as latency and errors that look like a system defect and are not. - **Read-only or non-identifying records** — search terms, product ids, geographies. `circular` or `random` is the right answer and the crash should never have been possible; the file being small is then a feature. If the run genuinely needs more distinct identities than you can provision, that is a test-data conversation rather than a Gatling setting, and the honest report is that the run could not be executed at the requested size. ## Making the next failure louder The deeper problem with this class of failure is that it is silent until it is fatal: nothing in the report, the console or the statistics counts down as the stock drains, and the first news is the crash. Two habits help. 1. **Write the arithmetic down next to the feeder.** A one-line comment stating the profile the file was sized for makes the next person who doubles the arrival rate notice what they have just invalidated. 2. **Treat stock size as part of the profile, not part of the data.** When a run's duration or rate changes, the feeder file is one of the things that has to change with it, in the same review. And be explicit in the report you write afterwards: a run that crashed on test data did not measure the system, and the eight minutes it did produce are a partial observation at best — the tail behaviour a thirty-minute run exists to find is precisely the part that never happened.
- Would switching that feeder to `shuffle` have made the run last longer?No. Shuffle permutes the same finite stock; it changes the order records go out in, not how many there are. The feeder empties after exactly the same number of feed executions and the run crashes at the same point.
- Does the crash fail a CI gate that reads assertion results?Not on its own. The run never reaches assertion evaluation, so there is no assertion verdict to be red — the failure surfaces as a crashed process instead. A gate built only on assertion output will see nothing, so it has to treat a run that did not complete as a failure in its own right.
- How do you size the stock for a closed injection profile?You cannot read it off the profile. A closed profile fixes concurrency, not arrivals, so how many scenarios complete in the window depends on how fast the target responds. Size against your fastest plausible response time, which is the worst case for stock consumption, and add headroom.
saying these in an interview costs you the question
- Provisioning rows for peak concurrency instead of total feed executions
- Switching identity-bearing credentials to circular just to stop the crash
- Believing a crashed run still produced an assertion verdict
- Forgetting that a feed inside a loop multiplies the records consumed