gRPC Methods

Learn how to use each method offered by the Gatling gRPC DSL

Summary

With gRPC, four types of methods can be defined: unary, server streaming, client streaming and bidirectional streaming. Different Gatling DSL methods can be used depending on the type of the gRPC method.

Unary Server Stream Client Stream Bidirectional Stream
Instantiate unary serverStream clientStream bidiStream
Add request headers asciiHeader(s)
binaryHeader(s)
header
asciiHeader(s)
binaryHeader(s)
header
asciiHeader(s)
binaryHeader(s)
header
asciiHeader(s)
binaryHeader(s)
header
Add call credentials callCredentials callCredentials callCredentials callCredentials
Add deadline deadlineAfter deadlineAfter deadlineAfter deadlineAfter
Add checks check check check check
Response time policy messageResponseTimePolicy messageResponseTimePolicy
Open stream implied by send start start
Send a message send send send send
Half-close stream implied by send halfClose halfClose
Wait for stream end awaitStreamEnd awaitStreamEnd awaitStreamEnd
Cancel stream cancel cancel cancel

gRPC Method Descriptor

The Gatling gRPC DSL will need a method descriptor, of type io.grpc.MethodDescriptor, to define each gRPC method used. The most common use case is to use generated code from a .proto specification file which describes the gRPC service, but the method descriptor could also be constructed by hand.

In all code examples on this page, we assume a method descriptor defined by Java code similar to this:

public final class ExampleServiceGrpc {
  public static MethodDescriptor<ExampleRequest, ExampleResponse> getExampleMethod() {
    // generated method descriptor code here
  }
}

Instantiate a gRPC request

Unary method calls

For unary gRPC methods, Gatling gRPC requests are declared with the unary keyword.

grpc(requestName) is the entrypoint for any gRPC request with the Gatling gRPC DSL. unary(methodDescriptor) then takes a method descriptor describing the gRPC method to call (which must describe a unary method).

     
// with a static value
grpc("request name").unary(ExampleServiceGrpc.getExampleMethod());
// with a Gatling EL string
grpc("#{requestName}").unary(ExampleServiceGrpc.getExampleMethod());
// with a function
grpc(session -> session.getString("requestName")).unary(ExampleServiceGrpc.getExampleMethod());
// with a static value
grpc("request name").unary(ExampleServiceGrpc.getExampleMethod())
// with a Gatling EL string
grpc("#{requestName}").unary(ExampleServiceGrpc.getExampleMethod())
// with a function
grpc { session -> session.getString("requestName") }.unary(ExampleServiceGrpc.getExampleMethod())
// with a static value
grpc("request name").unary(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a Gatling EL string
grpc("#{requestName}").unary(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a function
grpc(session => session("requestName").as[String]).unary(ExampleServiceGrpc.METHOD_EXAMPLE)

When you send a message, Gatling gRPC will automatically handle the client-side lifecycle of the underlying gRPC stream (open a stream, send a single message, half-close the stream) and wait for the server to respond and close the stream.

     
ScenarioBuilder scn = scenario("scenario name").exec(
  // Sends a request and awaits a response, similarly to regular HTTP requests
  grpc("request name")
    .unary(ExampleServiceGrpc.getExampleMethod())
    .send(new RequestMessage("hello"))
);
val scn = scenario("scenario name").exec(
  // Sends a request and awaits a response, similarly to regular HTTP requests
  grpc("request name")
    .unary(ExampleServiceGrpc.getExampleMethod())
    .send(RequestMessage ("hello"))
)
val scn = scenario("scenario name").exec(
  // Sends a request and awaits a response, similarly to regular HTTP requests
  grpc("request name")
    .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
    .send(RequestMessage("hello"))
)

Streaming method calls

For streaming gRPC methods, Gatling gRPC requests are declared with the serverStream, clientStream, and bidiStream keyword. Including one of them in a scenario creates a gRPC stream which may stay open for a long time, and allows you to perform several actions on the same stream at various times during the scenario’s execution.

Server Stream

grpc(requestName) is the entrypoint for any gRPC request with the Gatling gRPC DSL. serverStream(methodDescriptor) then takes a method descriptor describing the gRPC method to call (which must describe a server streaming method).

     
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod());
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.getExampleMethod());
// with a function
grpc(session -> session.getString("requestName")).serverStream(ExampleServiceGrpc.getExampleMethod());
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod())
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.getExampleMethod())
// with a function
grpc { session -> session.getString("requestName") }.serverStream(ExampleServiceGrpc.getExampleMethod())
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a function
grpc(session => session("requestName").as[String]).serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)

The typical lifecycle of a server stream consists of:

  • Sending a single message with the send method (this will also half-close the stream, signaling that the client will not send any more messages)
  • Waiting until the stream gets closed by the server with the awaitStreamEnd method
     
GrpcServerStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod());

ScenarioBuilder scn = scenario("scenario name").exec(
  stream.send(message),
  stream.awaitStreamEnd()
);
val stream = grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod())

val scn = scenario("scenario name").exec(
  stream.send(message),
  stream.awaitStreamEnd()
)
val stream = grpc("request name").serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)

val scn = scenario("scenario name").exec(
  stream.send(message),
  stream.awaitStreamEnd
)

If several server streams are opened concurrently by a virtual user, they must be given explicit stream names to differentiate them:

     
GrpcServerStreamingServiceBuilder<RequestMessage, ResponseMessage> stream1 =
  // specify streamName initially
  grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod(), "first-stream");
GrpcServerStreamingServiceBuilder<RequestMessage, ResponseMessage> stream2 =
  grpc("request name")
    .serverStream(ExampleServiceGrpc.getExampleMethod())
    // or use the streamName method
    .streamName("second-stream");

exec(
  stream1.send(message),
  stream2.send(message)
);
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .serverStream(ExampleServiceGrpc.getExampleMethod(), "first-stream")
val stream2 = grpc("request name")
  .serverStream(ExampleServiceGrpc.getExampleMethod())
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.send(message),
  stream2.send(message)
)
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .serverStream(ExampleServiceGrpc.METHOD_EXAMPLE, "first-stream")
val stream2 = grpc("request name")
  .serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.send(message),
  stream2.send(message)
)
// both streams are concurrently open at this point

Client Stream

grpc(requestName) is the entrypoint for any gRPC request with the Gatling gRPC DSL. clientStream(methodDescriptor) then takes a method descriptor describing the gRPC method to call (which must describe a client streaming method).

     
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod());
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.getExampleMethod());
// with a function
grpc(session -> session.getString("requestName")).serverStream(ExampleServiceGrpc.getExampleMethod());
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.getExampleMethod())
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.getExampleMethod())
// with a function
grpc { session -> session.getString("requestName") }.serverStream(ExampleServiceGrpc.getExampleMethod())
// with a static value
grpc("request name").serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a Gatling EL string
grpc("#{requestName}").serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a function
grpc(session => session("requestName").as[String]).serverStream(ExampleServiceGrpc.METHOD_EXAMPLE)

The typical lifecycle of a client stream consists of:

  • Opening the stream with the start method
  • Sending messages with the send method
  • Half-closing the stream with the halfClose method when done sending messages
  • Waiting until the stream gets closed by the server with the awaitStreamEnd method
     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("request name").clientStream(ExampleServiceGrpc.getExampleMethod());

ScenarioBuilder scn = scenario("scenario name").exec(
  stream.start(),
  stream.send(message1),
  stream.send(message2),
  stream.halfClose(),
  stream.awaitStreamEnd()
);
val stream = grpc("request name").clientStream(ExampleServiceGrpc.getExampleMethod())

val scn = scenario("scenario name").exec(
  stream.start(),
  stream.send(message1),
  stream.send(message2),
  stream.halfClose(),
  stream.awaitStreamEnd()
)
val stream = grpc("request name").clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)

val scn = scenario("scenario name").exec(
    stream.start,
    stream.send(message1),
    stream.send(message2),
    stream.halfClose,
  stream.awaitStreamEnd
)

If several client streams are opened concurrently by a virtual user, they must be given explicit stream names to differentiate them:

     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream1 =
  // specify streamName initially
  grpc("request name").clientStream(ExampleServiceGrpc.getExampleMethod(), "first-stream");
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream2 =
  grpc("request name")
    .clientStream(ExampleServiceGrpc.getExampleMethod())
    // or use the streamName method
    .streamName("second-stream");

exec(
  stream1.start(),
  stream2.start()
);
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .clientStream(ExampleServiceGrpc.getExampleMethod(), "first-stream")
val stream2 = grpc("request name")
  .clientStream(ExampleServiceGrpc.getExampleMethod())
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.start(),
  stream2.start()
)
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .clientStream(ExampleServiceGrpc.METHOD_EXAMPLE, "first-stream")
val stream2 = grpc("request name")
  .clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.start,
  stream2.start
)
// both streams are concurrently open at this point

Bidirectional Stream

grpc(requestName) is the entrypoint for any gRPC request with the Gatling gRPC DSL. bidiStream(methodDescriptor) then takes a method descriptor describing the gRPC method to call (which must describe a bidirectional streaming method).

     
// with a static value
grpc("request name").bidiStream(ExampleServiceGrpc.getExampleMethod());
// with a Gatling EL string
grpc("#{requestName}").bidiStream(ExampleServiceGrpc.getExampleMethod());
// with a function
grpc(session -> session.getString("requestName")).bidiStream(ExampleServiceGrpc.getExampleMethod());
// with a static value
grpc("request name").bidiStream(ExampleServiceGrpc.getExampleMethod())
// with a Gatling EL string
grpc("#{requestName}").bidiStream(ExampleServiceGrpc.getExampleMethod())
// with a function
grpc { session -> session.getString("requestName") }.bidiStream(ExampleServiceGrpc.getExampleMethod())
// with a static value
grpc("request name").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a Gatling EL string
grpc("#{requestName}").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)
// with a function
grpc(session => session("requestName").as[String]).bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)

The typical lifecycle of a bidirectional stream consists of:

  • Opening the stream with the start method
  • Sending messages with the send method
  • Half-closing the stream with the halfClose method when done sending messages
  • Waiting until the stream gets closed by the server with the awaitStreamEnd method
     
GrpcBidirectionalStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("request name").bidiStream(ExampleServiceGrpc.getExampleMethod());

ScenarioBuilder scn = scenario("scenario name").exec(
  stream.start(),
  stream.send(message1),
  stream.send(message2),
  stream.halfClose(),
  stream.awaitStreamEnd()
);
val stream = grpc("request name").bidiStream(ExampleServiceGrpc.getExampleMethod())

val scn = scenario("scenario name").exec(
  stream.start(),
  stream.send(message1),
  stream.send(message2),
  stream.halfClose(),
  stream.awaitStreamEnd()
)
val stream = grpc("request name").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)

val scn = scenario("scenario name").exec(
    stream.start,
    stream.send(message1),
    stream.send(message2),
    stream.halfClose,
  stream.awaitStreamEnd
)

If several bidirectional streams are opened concurrently by a virtual user, they must be given explicit stream names to differentiate them:

     
GrpcBidirectionalStreamingServiceBuilder<RequestMessage, ResponseMessage> stream1 =
  // specify streamName initially
  grpc("request name").bidiStream(ExampleServiceGrpc.getExampleMethod(), "first-stream");
GrpcBidirectionalStreamingServiceBuilder<RequestMessage, ResponseMessage> stream2 =
  grpc("request name")
    .bidiStream(ExampleServiceGrpc.getExampleMethod())
    // or use the streamName method
    .streamName("second-stream");

exec(
  stream1.start(),
  stream2.start()
);
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .bidiStream(ExampleServiceGrpc.getExampleMethod(), "first-stream")
val stream2 = grpc("request name")
  .bidiStream(ExampleServiceGrpc.getExampleMethod())
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.start(),
  stream2.start()
)
// both streams are concurrently open at this point
val stream1 = grpc("request name")
  // specify streamName initially
  .bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE, "first-stream")
val stream2 = grpc("request name")
  .bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)
  // or use the streamName method
  .streamName("second-stream")

exec(
  stream1.start,
  stream2.start
)
// both streams are concurrently open at this point

Methods reference

Add request headers

unary serverStream clientStream bidiStream

You can easily add ASCII format request headers (they will use the standard ASCII marshaller, io.grpc.Metadata#ASCII_STRING_MARSHALLER):

     
// Extracting a map of headers allows you to reuse these in several requests
Map<String, String> sentHeaders = new HashMap<>();
sentHeaders.put("header-1", "first value");
sentHeaders.put("header-2", "second value");

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Adds several headers at once
  .asciiHeaders(sentHeaders)
  // Adds another header, with a static value
  .asciiHeader("header").value("value")
  // with a Gatling EL string header value
  .asciiHeader("header").valueEl("#{headerValue}")
  // with a function value
  .asciiHeader("header").value(session -> session.getString("headerValue"));
// Extracting a map of headers allows you to reuse these in several requests
val sentHeaders = hashMapOf(
  "header-1" to "first value",
  "header-2" to "second value"
)

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Adds several headers at once
  .asciiHeaders(sentHeaders)
  // Adds another header, with a static value
  .asciiHeader("header").value("value")
  // with a Gatling EL string header value
  .asciiHeader("header").valueEl("#{headerValue}")
  // with a function value
  .asciiHeader("header").value { session -> session.getString("headerValue") }
// Extracting a map of headers allows you to reuse these in several requests
val sentHeaders = Map(
  "header-1" -> "first value",
  "header-2" -> "second value"
)

grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  // Adds several headers at once
  .asciiHeaders(sentHeaders)
  // Adds another header, with a static value
  .asciiHeader("header")("value")
  // with a Gatling EL string header value
  .asciiHeader("header")("#{headerValue}")
  // with a function value
  .asciiHeader("header")(session => session("headerValue").as[String])

Or binary format headers (they will use the standard binary marshaller, io.grpc.Metadata#BINARY_BYTE_MARSHALLER):

     
// Extracting a map of headers allows you to reuse these in several requests
Charset utf8 = StandardCharsets.UTF_8;
Map<String, byte[]> sentHeaders = new HashMap<>();
sentHeaders.put("header-1-bin", "first value".getBytes(utf8));
sentHeaders.put("header-2-bin", "second value".getBytes(utf8));

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Adds several headers at once
  .binaryHeaders(sentHeaders)
  // Adds another header, with a static value
  .binaryHeader("header-bin").value("value".getBytes(utf8))
  // with a Gatling EL string header value
  .binaryHeader("header-bin").valueEl("#{headerValue}")
  // with a function value
  .binaryHeader("header-bin").value(session -> session.get("headerValue"));
// Extracting a map of headers allows you to reuse these in several requests
val utf8 = StandardCharsets.UTF_8
val sentHeaders = hashMapOf(
  "header-1-bin" to "first value".toByteArray(utf8),
  "header-2-bin" to "second value".toByteArray(utf8)
)

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Adds several headers at once
  .binaryHeaders(sentHeaders)
  // Adds another header, with a static value
  .binaryHeader("header-bin").value("value".toByteArray(utf8))
  // with a Gatling EL string header value
  .binaryHeader("header-bin").valueEl("#{headerValue}")
  // with a function value
  .binaryHeader("header-bin").value { session -> session.get("headerValue") }
// Extracting a map of headers allows you to reuse these in several requests
val utf8 = StandardCharsets.UTF_8
val sentHeaders = Map(
  "header-1" -> "first value".getBytes(utf8),
  "header-2" -> "second value".getBytes(utf8)
)

grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  // Adds several headers at once
  .binaryHeaders(sentHeaders)
  // Adds another header, with a static value
  .binaryHeader("header")("value".getBytes(utf8))
  // with a Gatling EL string header value
  .binaryHeader("header-bin")("#{headerValue}")
  // with a function value
  .binaryHeader("header-bin")(session => session("headerValue").as[Array[Byte]])

If you need to use custom marshallers, you can add headers one at a time with your own io.grpc.Metadata.Key:

     
// Define custom marshallers (implementations not shown here)
Metadata.AsciiMarshaller<Integer> intToAsciiMarshaller = null;
Metadata.BinaryMarshaller<Double> doubleToBinaryMarshaller = null;

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Add headers one at a time (the type of the value must match the type
  // expected by the Key's serializer, e.g. Integer for the first one here)
  .header(Metadata.Key.of("header", intToAsciiMarshaller)).value(123)
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).value(4.56)
  // with a Gatling EL string header value
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).valueEl("#{headerValue}")
  // with a function value
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).value(session -> session.get("headerValue"));
// Define custom marshallers (implementations not shown here)
val intToAsciiMarshaller: Metadata.AsciiMarshaller<Int> = TODO()
val doubleToBinaryMarshaller: Metadata.BinaryMarshaller<Double> = TODO()

grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // Add headers one at a time (the type of the value must match the type
  // expected by the Key's serializer, e.g. Integer for the first one here)
  .header(Metadata.Key.of("header", intToAsciiMarshaller)).value(123)
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).value(4.56)
  // with a Gatling EL string header value
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).valueEl("#{headerValue}")
  // with a function value
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller)).value { session -> session.get("headerValue") }
// Define custom marshallers (implementations not shown here)
val intToAsciiMarshaller: Metadata.AsciiMarshaller[Int] = ???
val doubleToBinaryMarshaller: Metadata.BinaryMarshaller[Double] = ???

grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  // Add headers one at a time (the type of the value must match the type
  // expected by the Key's serializer, e.g. Int for the first one here)
  .header(Metadata.Key.of("header", intToAsciiMarshaller))(123)
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller))(4.56)
  // with a Gatling EL string header value
  .header[Double](Metadata.Key.of("header-bin", doubleToBinaryMarshaller))("#{headerValue}")
  // with a function value
  .header(Metadata.Key.of("header-bin", doubleToBinaryMarshaller))(session => session("headerValue").as[Double])

Note that in gRPC, headers are per-stream, not per-message. Even in client or bidirectional streaming methods, request headers are sent only once, when starting the stream:

     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name")
    .clientStream(ExampleServiceGrpc.getExampleMethod())
    .asciiHeader("header").value("value");

exec(
  stream.start(), // Header is sent only once, on stream start
  stream.send(message1),
  stream.send(message2)
);
val stream = grpc("name")
  .clientStream(ExampleServiceGrpc.getExampleMethod())
  .asciiHeader("header").value("value")

exec(
  stream.start(), // Header is sent only once, on stream start
  stream.send(message1),
  stream.send(message2)
)
val stream = grpc("request name")
  .clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)
  .asciiHeader("header")("value")

exec(
  stream.start, // Header is sent only once, on stream start
  stream.send(message1),
  stream.send(message2)
)

Also note that keys in gRPC headers are allowed to be associated with more than one value, so adding the same key a second time will simply add a second value, not replace the first one.

Add call credentials

unary serverStream clientStream bidiStream

You can specify call credentials by providing an instance of io.grpc.CallCredentials. This will override any value set on the protocol.

     
grpc("name")
    .unary(ExampleServiceGrpc.getExampleMethod())
    .send(message)
    // with a constant
    .callCredentials(callCredentials)
    // or with an EL string to retrieve CallCredentials already stored in the session
    .callCredentials("#{callCredentials}")
    // or with a function
    .callCredentials(session -> {
      var name = session.getString("myUserName");
      return callCredentialsForUser(name);
    });
grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // with a constant
  .callCredentials(callCredentials)
  // or with an EL string to retrieve CallCredentials already stored in the session
  .callCredentials("#{callCredentials}")
  // or with a function
  .callCredentials { session ->
    val name = session.getString("myUserName")!!
    callCredentialsForUser(name)
  }
grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  // with a constant
  .callCredentials(callCredentials)
  // or with an EL string to retrieve CallCredentials already stored in the session
  .callCredentials("#{callCredentials}")
  // or with a function
  .callCredentials { session =>
    val name = session("myUserName").as[String]
    callCredentialsForUser(name)
  }

Add deadline

unary serverStream clientStream bidiStream

You can specify a deadline to use for the request:

     
grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // with a number of seconds
  .deadlineAfter(10)
  // or with a java.time.Duration
  .deadlineAfter(Duration.ofSeconds(10));
grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  // with a number of seconds
  .deadlineAfter(10)
  // or with a java.time.Duration
  .deadlineAfter(Duration.ofSeconds(10))
grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  // with a number of seconds
  .deadlineAfter(10)
  // or with a scala.concurrent.duration.FiniteDuration
  .deadlineAfter(10.seconds)

The actual deadline will be computed just before the start of each gRPC request based on the provided duration.

Add checks

unary serverStream clientStream bidiStream

You can specify one or more checks, to be applied to the response headers, trailers, status, or message:

     
grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  .check(
    statusCode().is(Status.Code.OK),
    response(ResponseMessage::getMessage).is("hello")
  );
grpc("name")
  .unary(ExampleServiceGrpc.getExampleMethod())
  .send(message)
  .check(
    statusCode().shouldBe(Status.Code.OK),
    response(ResponseMessage::getMessage).shouldBe("hello")
  )
grpc("name")
  .unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(message)
  .check(
    statusCode.is(Status.Code.OK),
    response((result: ResponseMessage) => result.message).is("hello")
  )

See the checks section for more details on gRPC checks.

If you define response checks for server or bidirectional streaming methods, they will be applied to every message received from the server. Other checks are only applied once, at the end of the stream.

Response time policy

serverStream clientStream bidiStream

For streaming methods only, you can specify how to calculate the response time logged for each response message received.

  • FromStreamStartPolicy: measure the time since the start of the entire stream. When receiving several response messages on the same stream, they show increasing response times. This is the default because it can always be computed as expected, but it may not be what you are interested in for long-lived server or bidirectional streams.
  • FromLastMessageSentPolicy: measure the time since the last request message was sent. If no request message was sent previously, falls back to FromStreamStartPolicy.
  • FromLastMessageReceivedPolicy: measure the time since the previous response message was received. If this is the first response message received, falls back to FromStreamStartPolicy.
     
grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod())
  // Default: from the start of the entire stream
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromStreamStart)
  // From the time when the last request message was sent
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromLastMessageSent)
  // From the time the previous response message was received
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromLastMessageReceived);
grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod())
  // Default: from the start of the entire stream
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromStreamStart)
  // From the time when the last request message was sent
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromLastMessageSent)
  // From the time the previous response message was received
  .messageResponseTimePolicy(MessageResponseTimePolicy.FromLastMessageReceived)
grpc("name").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)
  // Default: from the start of the entire stream
  .messageResponseTimePolicy(FromStreamStartPolicy)
  // From the time when the last request message was sent
  .messageResponseTimePolicy(FromLastMessageSentPolicy)
  // From the time the previous response message was received
  .messageResponseTimePolicy(FromLastMessageReceivedPolicy)

Open stream

clientStream bidiStream

For client or bidirectional streaming methods only, you must start the stream to signal that the client is ready to send messages. Only then can you send messages and/or half-close the stream.

     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod());

exec(stream.start());
val stream = grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod())

exec(stream.start())
val stream = grpc("name").clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)

exec(stream.start)

Send a message

unary serverStream clientStream bidiStream

The message sent must be of the type specified in the method descriptor for outbound messages. You can pass a static message, or a function to construct the message from the Gatling Session.

     
// with a static payload
grpc("name").unary(ExampleServiceGrpc.getExampleMethod())
  .send(new RequestMessage("hello"));
// with a function payload
grpc("name").unary(ExampleServiceGrpc.getExampleMethod())
  .send(session -> new RequestMessage(session.getString("message")));
// with a static payload
grpc("name").unary(ExampleServiceGrpc.getExampleMethod())
  .send(RequestMessage("hello"))
// with a function payload
grpc("name").unary(ExampleServiceGrpc.getExampleMethod())
  .send { session -> RequestMessage(session.getString("message")) }
// with a static payload
grpc("name").unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(RequestMessage("hello"))
// with a function payload
grpc("name").unary(ExampleServiceGrpc.METHOD_EXAMPLE)
  .send(session => RequestMessage(session("message").as[String]))

For client streaming and bidirectional streaming methods, you can send several messages.

     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod());

exec(
  stream.send(new RequestMessage("first message")),
  stream.send(new RequestMessage("second message")),
  stream.send(session -> new RequestMessage(session.getString("third-message")))
);
val stream = grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod())

exec(
  stream.send(RequestMessage("first message")),
  stream.send(RequestMessage("second message")),
  stream.send { session -> RequestMessage(session.getString("third-message")) }
)
val stream = grpc("name").clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)

exec(
  stream.send(RequestMessage("first message")),
  stream.send(RequestMessage("second message")),
  stream.send(session => RequestMessage(session("third-message").as[String]))
)

Half-close stream

clientStream bidiStream

For client or bidirectional streaming methods only, you can half-close the stream to signal that the client has finished sending messages. You can then no longer use the send method on the same stream.

     
GrpcClientStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod());

exec(stream.halfClose());
val stream = grpc("name").clientStream(ExampleServiceGrpc.getExampleMethod())

exec(stream.halfClose())
val stream = grpc("name").clientStream(ExampleServiceGrpc.METHOD_EXAMPLE)

exec(stream.halfClose)

Wait for stream end

serverStream clientStream bidiStream

For streaming methods only, you can use the awaitStreamEnd method to wait until the server closes the connection. During that time, you may also still receive response messages from the server.

     
GrpcBidirectionalStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod());

exec(stream.awaitStreamEnd());
val stream = grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod())

exec(stream.awaitStreamEnd())
val stream = grpc("name").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)

exec(stream.awaitStreamEnd)

Cancel stream

serverStream clientStream bidiStream

For streaming methods only, you can use the cancel method to cancel the gRPC stream and prevent any further processing.

     
GrpcBidirectionalStreamingServiceBuilder<RequestMessage, ResponseMessage> stream =
  grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod());

exec(stream.cancel());
val stream = grpc("name").bidiStream(ExampleServiceGrpc.getExampleMethod())

exec(stream.cancel())
val stream = grpc("name").bidiStream(ExampleServiceGrpc.METHOD_EXAMPLE)

exec(stream.cancel)

Edit this page on GitHub