Controlled‑Rate Load Testing with Gatling Feeders and constantUsersPerSec
Learn how to combine Gatling’s CSV feeder with a constantUsersPerSec injection profile to run a steady‑rate load test, including setup, execution checks, and practical limitations.
13 Aug 2025, 17:38 UTC

Desired outcome
Run a Gatling simulation that injects a fixed number of virtual users per second, feeds each user with a unique record from an external CSV file, and validates that each request returns HTTP 200. The test provides a steady arrival rate so you can measure throughput or latency under controlled load.
Prerequisites
- Gatling 3.x installed (bundle or via Maven/Gradle).
- A CSV file (e.g.,
users.csv) placed insrc/test/resources/data/with a header row and at least as many rows as the expected number of requests. - A local mock HTTP endpoint that returns 200 for GET requests (e.g., a simple WireMock stub or a lightweight Node/Express server).
- Basic familiarity with Scala syntax and the Gatling DSL.
- Sufficient heap space for the feeder; for files larger than a few hundred KB consider a JDBC feeder or batching.
Procedure
1. Prepare the feeder
Define a queue‑based feeder that will serve each record once, in order.
val csvFeeder = csv("data/users.csv").queue
2. Build the scenario
Each virtual user takes a record from the feeder, performs an HTTP GET, and checks the response status.
val httpProtocol = http
.baseUrl("http://localhost:8080") // adjust to your mock endpoint
.acceptHeader("text/html,application/json")
val scn = scenario("ControlledRateGet")
.feed(csvFeeder)
.exec(
http("GetResource")
.get("/resource/${id}") // assumes CSV column named 'id'
.check(status.is(200))
)
3. Configure the injection profile
Use constantUsersPerSec to inject a steady flow of users for a defined duration.
setUp(
scn.inject(constantUsersPerSec(5).during(10.seconds))
).protocols(httpProtocol)
This configuration attempts to start 5 new users every second, for a total of 10 seconds → up to 50 users (subject to feeder availability).
4. Run the simulation
From the project root, execute:
./gatling.sh -s com.example.ControlledRateGetSimulationIf you use Maven:
mvn gatling:test -Dgatling.simulationClass=com.example.ControlledRateGetSimulationRun the command with a user that has read access to the CSV and permission to bind to the mock endpoint’s port.
5. Expected checks
- Console output should show lines like:
Feeder: csv data/users.csv (queue) - 50 recordsconstantUsersPerSec: 5.0 users/sec during 10.0sRequests: 50 OK, 0 KO
- The generated report under
target/gatling/results//index.htmlshould display a “Requests” table with the total count matching the number of feeder records consumed (or fewer if the feeder runs out early). All status checks should be reported as passed.
6. Practical verification
- Open the report and confirm that the “Summary” section shows
# requests = 50(or the actual number fed). - Check the “Errors” tab – it should be empty.
- Optionally, add a custom check to verify a field from the CSV appears in the response (e.g.,
.check(jsonPath("$.id").is(${id}))) and re‑run to see it reflected in the report.
Limitations
- Feeder memory: Queue feeders materialize the entire CSV in memory. Very large files may cause heap pressure; consider switching to a JDBC feeder or reading the file in chunks.
- Think‑time interference:
constantUsersPerSecdoes not pause for think‑time. AnypauseorthinkTimeinside the scenario reduces the offered load below the configured rate. If you need think‑time, add it separately or adjust the injection rate upward. - Check overhead: Complex
jsonPathorregexchecks add CPU cost. Profile them with a short dry‑run before scaling to higher rates.
Recovery options
Running the simulation does not modify persistent state (assuming the mock endpoint is stateless). If the test inadvertently targets a production service, stop the test immediately with Ctrl+C in the terminal, verify the service’s health, and, if needed, restore any altered data from backups or re‑run idempotent setup scripts.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.