Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gatling/gatling.io-doc/llms.txt

Use this file to discover all available pages before exploring further.

gRPC is the de-facto standard for inter-service communication in microservice architectures. Its use of Protocol Buffers and HTTP/2 makes it fast and strongly typed, but those same characteristics make it more complex to load test than a plain HTTP API. Gatling’s dedicated gRPC SDK lets you write expressive, code-based load tests for unary, client-streaming, server-streaming, and bidirectional gRPC methods. This guide walks through a complete simulation that tests both a basic unary call and deadline-enforced behaviour.

Prerequisites

  • Gatling version 3.13 or higher with the gRPC SDK
  • Java 17 or higher
  • Maven or Gradle
  • A running gRPC server — clone the gatling/gatling-grpc-demo repository to get a ready-made server with TLS certificates

Project Setup

Clone the demo and open GreetingSimulation in your IDE:
git clone https://github.com/gatling/gatling-grpc-demo
cd gatling-grpc-demo
Start the demo gRPC server:
./certificates
cd server
./gradlew -PmainClass=io.gatling.grpc.demo.server.greeting.GreetingServer run

Understanding the Proto Definition

The demo exposes a GreetingService with two RPC methods defined in a Protocol Buffer schema:
  • Greet — takes a first and last name, returns a greeting string (unary)
  • GreetWithDeadline — same interface, but the client should enforce a strict deadline to verify timeout handling

Protocol Configuration

Set up the gRPC protocol builder to connect to the server and configure channel credentials:
import io.gatling.javaapi.grpc.*;
import static io.gatling.javaapi.grpc.GrpcDsl.*;

GrpcProtocolBuilder baseGrpcProtocol = grpc
  .forAddress("localhost", 50051)
  .channelCredentials("#{channelCredentials}")
  .overrideAuthority("gatling-grpc-demo-test-server");
The channelCredentials value is injected per virtual user from a feeder, enabling each user to authenticate independently.

Scenario 1: Unary Greeting

1

Build the session-aware greeting function

Create a Function that reads firstName and lastName from the virtual user’s session and constructs the Greeting Protobuf object:
import java.util.function.Function;

Function<Session, Greeting> greeting = session -> {
  String firstName = session.getString("firstName");
  String lastName  = session.getString("lastName");
  return Greeting.newBuilder()
      .setFirstName(firstName)
      .setLastName(lastName)
      .build();
};
2

Write the unary scenario

ScenarioBuilder unary = scenario("Greet Unary")
  .feed(Feeders.channelCredentials().circular())  // TLS credentials
  .feed(Feeders.randomNames())                    // firstName, lastName
  .exec(grpc("Greet")
    .unary(GreetingServiceGrpc.getGreetMethod())
    .send(session -> GreetRequest.newBuilder()
        .setGreeting(greeting.apply(session))
        .build())
    .check(
      statusCode().is(Status.Code.OK),
      response(GreetResponse::getResult)
        .isEL("Hello #{firstName} #{lastName}")
    )
  );
Key elements:
  • .unary() — invokes a unary (single request/single response) RPC method
  • .send() — builds the request message from the session
  • .check(statusCode().is(OK)) — validates the gRPC status code
  • .check(response(...).isEL(...)) — verifies the response payload using the Expression Language

Scenario 2: Deadline Handling

A deadline tells the gRPC client to abort and return DEADLINE_EXCEEDED if the server does not respond within the specified duration. Load testing deadline behaviour verifies that your server respects client-imposed timeouts and that the error is propagated correctly.
ScenarioBuilder deadlines = scenario("Greet w/ Deadlines")
  .feed(Feeders.channelCredentials().circular())
  .feed(Feeders.randomNames())
  .exec(grpc("Greet w/ Deadlines")
    .unary(GreetingServiceGrpc.getGreetWithDeadlineMethod())
    .send(session -> GreetRequest.newBuilder()
        .setGreeting(greeting.apply(session))
        .build())
    .deadlineAfter(Duration.ofMillis(100))         // Enforce 100 ms deadline
    .check(statusCode().is(Status.Code.DEADLINE_EXCEEDED))
  );
Deadlines prevent requests from hanging indefinitely. Load testing with deadlines reveals whether your service fails fast under latency pressure rather than leaving clients waiting.

Injection Profile and setUp

Use a system property to switch between the two scenarios at run time:
{
  String name = System.getProperty("grpc.scenario", "unary");
  ScenarioBuilder scn = "deadlines".equals(name) ? deadlines : unary;

  setUp(
    scn.injectOpen(atOnceUsers(5))
  ).protocols(baseGrpcProtocol);
}

Running the Simulation

# Run the unary scenario
./mvnw gatling:test \
  -Dgrpc.scenario=unary \
  -Dgatling.simulationClass=io.gatling.grpc.demo.GreetingSimulation

# Run the deadlines scenario
./mvnw gatling:test \
  -Dgrpc.scenario=deadlines \
  -Dgatling.simulationClass=io.gatling.grpc.demo.GreetingSimulation
After the run completes, Gatling prints an HTML report link to the terminal.

Interpreting gRPC Metrics in Reports

gRPC simulations report using the same response-time and error-rate metrics as HTTP simulations. Key things to look for:

Status code distribution

Unexpected UNAVAILABLE or INTERNAL codes often indicate server-side resource exhaustion under load.

p99 response times

gRPC services typically have strict latency SLAs. A p99 spike that stays within deadline bounds is healthy; one that exceeds the deadline will trigger DEADLINE_EXCEEDED errors.

Connection errors

High connection error rates suggest that the server’s maximum concurrent stream count or connection pool is too small for the injected load.

DEADLINE_EXCEEDED rate

In the deadline scenario, 100% of requests should return DEADLINE_EXCEEDED. A lower rate indicates the server responded faster than expected — which may mean your deadline is too lenient.

References

Build docs developers (and LLMs) love