Impact of Downstream Integration on Gatling Request Stability and Throughput Consistency

Gatling requests are suddenly impacted, for example, they start failing, slowing down, or producing inconsistent results—when an additional downstream system is introduced into the request pipeline. This change appears to cause fluctuations in the request rate. Previously, the setup worked perfectly with only one target system.

Below are the scenarios I’ve tested, along with their outcomes. While some approaches come close to working reliably, there are still noticeable dips in request consistency:

  1. constantUsersPerSec(20.10).during(15.minutes) :cross_mark:
  2. rampUsersPerSec(0.1).to(20).during(10.seconds),
    constantUsersPerSec(20).during(15.minutes) :cross_mark:
  3. atOnceUsers(21) :white_check_mark:

If receiving responses is an issue, how can Gatling guarantee a steady 20 transactions per second (TPS) without waiting for responses i.e. sending requests irrespective of response times? Is this the expected behavior from Gatling, or is it common across other performance testing tools as well?

when an additional downstream system is introduced into the request pipeline

What do you mean? What is an “additional downstream system”? What is a “request pipeline”?

It means there is an API call made to one downstream system through Gatling, which then forwards the request to another downstream system. When Gatling interacts with just the first downstream system, everything works fine, and we get a steady response rate close to 20 TPS. However, when the second downstream system is integrated, the Gatling request rate intermittently drops and then recovers. I’m trying to understand what’s causing this fluctuation in the request rate.

In an open model like you’re using, response times and virtual users arrival rate are completely uncorrelated.

What happens here is that you are introducing a correlation between response times and request rate because you are making your virtual users perform multiple requests sequentially, for example by making your virtual users loop.

You cannot control the request rate and make your virtual users perform multiple requests. It neither makes sense nor is possible.

If you want to control the request rate, you must make your virtual users perform one single request.
And if you cannot do that because there’s a logical sequence between requests, it means you cannot control the request rate, that’s not how your real world system works.

Depending on what you’re trying to achieve, you might want to share the connections, but only if that’s how your real world system behaves.

I’m using throttling to control the RPS throughout the execution, with the expectation of achieving a steady 20 TPS.

I’m sharing the script details in case it helps bring more clarity to the query I posted.

val csvFeeder = csv("../test.csv").circular

val sendRequest = scenario("Send Request")
    .forever(
     feed(csvFeeder)
    .exec(
      http("Request")
        .post("${BaseUrl}")
        .header("Key", "Value")
        .body(StringBody("${reqBody}")).asJson
        .check(
          status.is(200)
        )
    )
  )

  setUp(
    sendRequest.inject(    
      nothingFor(4.seconds),
      atOnceUsers(21)
    ).protocols(protocol)
    .throttle(
    reachRps(21).in(5.seconds),
    holdFor(16.minutes) 
  )
  ).maxDuration(16.minutes)

That’s exactly what I’m saying: forever loop hence sequential requests.

Note: don’t use throttle. I implemented it because people insisted on having JMeter plugins’ UltimateThreadGroup ported and it’s broken the same way. I’m considering deprecating it for removal.

Please check the warnings in the documentation, they are very explicit it should only be used with single request scenario, which yours isn’t: Gatling Simulation scripting reference

slandelle, would you be able to share the new simulation script, like I did in the last chat, so I can try it out?

Also, the request rate drops only for about 10–15 seconds at any point of time during the process once; otherwise, it consistently remains at 20 requests and 20 response per second for the rest of the 16-minute test duration with the above script. I need to understand how to control the drop.

My company and I make a living with Gatling, so we can only code for you if you are a customer.

Basically, you have to replace your throttle with an injection profile with the same shape and remove your loop from your scenario.