gRPC services can be injected in your application code.
Consuming gRPC services requires the gRPC classes to be generated.
Place your proto files in src/main/proto and run mvn compile .
|
Stubs and Injection
gRPC generation provides several stubs, providing different way to consume a service. Quarkus gRPC can inject:
-
blocking stubs
-
reactive stubs based on Mutiny
In addition, it also can inject the gRPC io.grpc.Channel
, that lets you create other types of stubs.
@Inject @GrpcService("hello-service")
MutinyGreeterGrpc.MutinyGreeterStub mutiny;
@Inject @GrpcService("hello-service")
GreeterGrpc.GreeterBlockingStub blocking;
@Inject @GrpcService("hello-service")
Channel channel;
The stub class names are computed from the service name.
For example, if you use Greeter
as service name as in:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
The Mutiny stub name is: MutinyGreeterGrpc.MutinyGreeterStub
The blocking stub name is: GreeterGrpc.GreeterBlockingStub
Client injection must be qualified using @GrpcService
.
This annotation indicates the configuration prefix used to configure the service.
For example, if you set it to hello-service
, configuring the host of the service is done using hello-service.host
.
Examples
Using a blocking and mutiny stubs
@Inject @GrpcService("hello") GreeterGrpc.GreeterBlockingStub blockingHelloService;
@Inject @GrpcService("hello") MutinyGreeterGrpc.MutinyGreeterStub mutinyHelloService;
@GET
@Path("/blocking/{name}")
public String helloBlocking(@PathParam("name") String name) {
return blockingHelloService.sayHello(HelloRequest.newBuilder().setName(name).build()).getMessage();
}
@GET
@Path("/mutiny/{name}")
public Uni<String> helloMutiny(@PathParam("name") String name) {
return mutinyHelloService.sayHello(HelloRequest.newBuilder().setName(name).build())
.onItem().transform(HelloReply::getMessage);
}
Note that in this example, the quarkus.grpc.clients.hello.host
property must be set.
Handling streams
gRPC allows sending and receiving streams:
service Streaming {
rpc Source(Empty) returns (stream Item) {} // Returns a stream
rpc Sink(stream Item) returns (Empty) {} // Reads a stream
rpc Pipe(stream Item) returns (stream Item) {} // Reads a streams and return a streams
}
Using the Mutiny stub, you can interact with these as follows:
package io.quarkus.grpc.example.streaming;
import io.grpc.examples.streaming.Empty;
import io.grpc.examples.streaming.Item;
import io.grpc.examples.streaming.MutinyStreamingGrpc;
import io.quarkus.grpc.runtime.annotations.GrpcService;
import io.smallrye.mutiny.Multi;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/streaming")
@Produces(MediaType.APPLICATION_JSON)
public class StreamingEndpoint {
@Inject @GrpcService("streaming") MutinyStreamingGrpc.MutinyStreamingStub client;
@GET
public Multi<String> invokeSource() {
// Retrieve a stream
return client.source(Empty.newBuilder().build())
.onItem().transform(Item::getValue);
}
@GET
@Path("sink/{max}")
public Uni<Void> invokeSink(@PathParam("max") int max) {
// Send a stream and wait for completion
Multi<Item> inputs = Multi.createFrom().range(0, max)
.map(i -> Integer.toString(i))
.map(i -> Item.newBuilder().setValue(i).build());
return client.sink(inputs).onItem().ignore().andContinueWithNull();
}
@GET
@Path("/{max}")
public Multi<String> invokePipe(@PathParam("max") int max) {
// Send a stream and retrieve a stream
Multi<Item> inputs = Multi.createFrom().range(0, max)
.map(i -> Integer.toString(i))
.map(i -> Item.newBuilder().setValue(i).build());
return client.pipe(inputs).onItem().transform(Item::getValue);
}
}
Client configuration
For each gRPC service you inject in your application, you can configure the following attributes:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
The gRPC service port. |
int |
|
The host name / IP on which the service is exposed. |
string |
required |
The classpath path or file path to a server certificate or certificate chain in PEM format. |
path |
|
The classpath path or file path to the corresponding certificate private key file in PEM format. |
path |
|
An optional trust store which holds the certificate information of the certificates to trust The trust store can be either on classpath or in an external file. |
path |
|
Whether |
boolean |
|
The duration after which a keep alive ping is sent. |
||
The flow control window in bytes. Default is 1MiB. |
int |
|
The duration without ongoing RPCs before going to idle mode. |
||
The amount of time the sender of of a keep alive ping waits for an acknowledgement. |
||
Whether keep-alive will be performed when there are no outstanding RPC on a connection. |
boolean |
|
The max number of hedged attempts. |
int |
|
The max number of retry attempts. Retry must be explicitly enabled. |
int |
|
The maximum number of channel trace events to keep in the tracer for each channel or sub-channel. |
int |
|
The maximum message size allowed for a single gRPC frame (in bytes). Default is 4 MiB. |
int |
|
The maximum size of metadata allowed to be received (in bytes). Default is 8192B. |
int |
|
The negotiation type for the HTTP/2 connection. Accepted values are: |
string |
|
Overrides the authority used with TLS and HTTP virtual hosting. |
string |
|
The per RPC buffer limit in bytes used for retry. |
long |
|
Whether retry is enabled. Note that retry is disabled by default. |
boolean |
|
The retry buffer size in bytes. |
long |
|
Use a custom user-agent. |
string |
About the Duration format
The format for durations uses the standard You can also provide duration values starting with a number.
In this case, if the value consists only of a number, the converter treats the value as seconds.
Otherwise, |
The service-name
is the name set in the @GrpcService
.
Example of configuration
The 2 following examples uses hello as service name.
Don’t forget to replace it with the name you used in in the @GrpcService
annotation.
Enabling TLS
To enable TLS, use the following configuration.
Note that all paths in the configuration may either specify a resource on the classpath
(typically from src/main/resources
or its subfolder) or an external file.
quarkus.grpc.clients.hello.host=localhost
# either a path to a classpath resource or to a file:
quarkus.grpc.clients.hello.ssl.trust-store=tls/ca.pem
When SSL/TLS is configured, plain-text is automatically disabled.
|
TLS with Mutual Auth
To use TLS with mutual authentication, use the following configuration:
quarkus.grpc.clients.hello.host=localhost
quarkus.grpc.clients.hello.plain-text=false
# all the following may use either a path to a classpath resource or to a file:
quarkus.grpc.clients.hello.ssl.certificate=tls/client.pem
quarkus.grpc.clients.hello.ssl.key=tls/client.key
quarkus.grpc.clients.hello.ssl.trust-store=tls/ca.pem