Skip to content

Commit fca746c

Browse files
committed
Documentation and improvements
1 parent 407888e commit fca746c

File tree

27 files changed

+679
-186
lines changed

27 files changed

+679
-186
lines changed

vertx-grpc-client/src/main/asciidoc/client.adoc

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
== Vert.x gRPC Client
22

3-
Vert.x gRPC Client is a new gRPC client powered by Vert.x HTTP client superseding the integrated Netty based gRPC client.
3+
Vert.x gRPC Client is a gRPC client powered by Vert.x HTTP client.
44

5-
This client provides a gRPC request/response oriented API as well as a the generated stub approach with a gRPC Channel
5+
This client provides a gRPC request/response oriented API as well as a generated stub approach with a gRPC Channel
66

77
=== Using Vert.x gRPC Client
88

@@ -41,7 +41,7 @@ You can easily create the gRPC client
4141

4242
==== Request/response
4343

44-
Any interaction with a gRPC server involves creating a request to the remote gRPC service
44+
Interacting with a gRPC server involves creating a request to the remote gRPC service
4545

4646
[source,java]
4747
----
@@ -65,7 +65,7 @@ Future composition can combine all the previous steps together in a compact fash
6565

6666
==== Streaming request
6767

68-
A streaming request involves calling `{@link io.vertx.grpc.client.GrpcClientRequest#write}` for each element of the stream
68+
Streaming requests involve calling `{@link io.vertx.grpc.client.GrpcClientRequest#write}` for each element of the stream
6969
and using `{@link io.vertx.grpc.client.GrpcClientRequest#end()}` to end the stream
7070

7171
[source,java]
@@ -75,7 +75,7 @@ and using `{@link io.vertx.grpc.client.GrpcClientRequest#end()}` to end the stre
7575

7676
==== Streaming response
7777

78-
You can set handlers to process response events
78+
You can set handlers to process response events of a streaming response
7979

8080
[source,java]
8181
----
@@ -104,6 +104,26 @@ You can pause/resume/fetch a response
104104
{@link examples.GrpcClientExamples#responseFlowControl}
105105
----
106106

107+
=== Timeout and deadlines
108+
109+
The gRPC client handles timeout and deadlines, setting a timeout on a gRPC request instructs the client to send the timeout
110+
information to make the server aware that the client desires a response within a defined time.
111+
112+
In addition, the client shall be configured to schedule a deadline: when a timeout is set on a request, the client schedules
113+
locally a timer to cancel the request when the response has not been received in time.
114+
115+
[source,java]
116+
----
117+
{@link examples.GrpcClientExamples#requestWithDeadline}
118+
----
119+
120+
The timeout can also be set on a per-request basis.
121+
122+
[source,java]
123+
----
124+
{@link examples.GrpcClientExamples#requestWithDeadline2}
125+
----
126+
107127
=== Cancellation
108128

109129
You can call `{@link io.vertx.grpc.client.GrpcClientRequest#cancel}` to cancel a request
@@ -126,17 +146,28 @@ You can compress request messages by setting the request encoding *prior* before
126146

127147
=== Decompression
128148

129-
Decompression is done transparently by the client when the server send encoded responses.
149+
Decompression is achieved transparently by the client when the server sends encoded responses.
130150

131151
=== Stub API
132152

133153
The Vert.x gRPC Client provides a gRPC channel to use with a generated client stub in a more traditional fashion
134154

135155
[source,java]
136156
----
137-
{@link examples.GrpcClientExamples#stubExample}
157+
{@link examples.GrpcClientExamples#stub}
138158
----
139159

160+
Timeout and deadlines are supported through the usual gRPC API.
161+
162+
[source,java]
163+
----
164+
{@link examples.GrpcClientExamples#stubWithDeadline}
165+
----
166+
167+
Deadline are cascaded, e.g. when the current `io.grpc.Context` carries a deadline and the stub has no explicit deadline
168+
set, the client automatically inherits the implicit deadline. Such deadline can be set when using a stub within a gRPC server
169+
call.
170+
140171
=== Message level API
141172

142173
The client provides a message level API to interact directly with protobuf encoded gRPC messages.

vertx-grpc-client/src/main/java/examples/GrpcClientExamples.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
import io.vertx.core.buffer.Buffer;
88
import io.vertx.core.net.SocketAddress;
99
import io.vertx.docgen.Source;
10-
import io.vertx.grpc.client.GrpcClient;
11-
import io.vertx.grpc.client.GrpcClientChannel;
12-
import io.vertx.grpc.client.GrpcClientRequest;
13-
import io.vertx.grpc.client.GrpcClientResponse;
10+
import io.vertx.grpc.client.*;
1411
import io.vertx.grpc.common.GrpcMessage;
1512
import io.vertx.grpc.common.ServiceName;
1613

14+
import java.util.concurrent.TimeUnit;
15+
1716
@Source
1817
public class GrpcClientExamples {
1918

@@ -122,26 +121,61 @@ public void requestCompression(GrpcClientRequest<Item, Empty> request) {
122121
request.write(Item.newBuilder().setValue("item-3").build());
123122
}
124123

125-
public void stubExample(GrpcClient client) {
124+
public void stub(GrpcClient client) {
126125

127126
GrpcClientChannel channel = new GrpcClientChannel(client, SocketAddress.inetSocketAddress(443, "example.com"));
128127

129128
GreeterGrpc.GreeterStub greeter = GreeterGrpc.newStub(channel);
130129

131-
greeter.sayHello(HelloRequest.newBuilder().setName("Bob").build(), new StreamObserver<HelloReply>() {
130+
StreamObserver<HelloReply> observer = new StreamObserver<HelloReply>() {
132131
@Override
133132
public void onNext(HelloReply value) {
134133
// Process response
135134
}
135+
136136
@Override
137137
public void onCompleted() {
138138
// Done
139139
}
140+
140141
@Override
141142
public void onError(Throwable t) {
142143
// Something went bad
143144
}
145+
};
146+
147+
greeter.sayHello(HelloRequest.newBuilder().setName("Bob").build(), observer);
148+
}
149+
150+
public void stubWithDeadline(GrpcClientChannel channel, StreamObserver<HelloReply> observer) {
151+
152+
GreeterGrpc.GreeterStub greeter = GreeterGrpc.newStub(channel).withDeadlineAfter(10, TimeUnit.SECONDS);
153+
154+
greeter.sayHello(HelloRequest.newBuilder().setName("Bob").build(), observer);
155+
}
156+
157+
public void requestWithDeadline(Vertx vertx) {
158+
159+
// Set a 10 seconds timeout that will be sent to the gRPC service
160+
// Let the client schedule a deadline
161+
GrpcClient client = GrpcClient.client(vertx, new GrpcClientOptions()
162+
.setTimeout(10)
163+
.setTimeoutUnit(TimeUnit.SECONDS)
164+
.setScheduleDeadlineAutomatically(true));
165+
}
166+
167+
public void requestWithDeadline2(GrpcClient client, SocketAddress server, MethodDescriptor<HelloRequest, HelloReply> sayHelloMethod) {
168+
169+
Future<GrpcClientRequest<HelloRequest, HelloReply>> fut = client.request(server, sayHelloMethod);
170+
fut.onSuccess(request -> {
171+
172+
request
173+
// Given this request, set a 10 seconds timeout that will be sent to the gRPC service
174+
.timeout(10, TimeUnit.SECONDS);
175+
176+
request.end(HelloRequest.newBuilder().setName("Bob").build());
144177
});
178+
145179
}
146180

147181
public void protobufLevelAPI(GrpcClient client, Buffer protoHello, SocketAddress server) {

vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClient.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ static GrpcClient client(Vertx vertx) {
5252
return new GrpcClientImpl(vertx);
5353
}
5454

55+
/**
56+
* Create a client.
57+
*
58+
* @param vertx the vertx instance
59+
* @return the created client
60+
*/
61+
static GrpcClient client(Vertx vertx, GrpcClientOptions options) {
62+
return new GrpcClientImpl(vertx, options, new HttpClientOptions().setHttp2ClearTextUpgrade(false));
63+
}
64+
65+
/**
66+
* Create a client with the specified {@code options}.
67+
*
68+
* @param vertx the vertx instance
69+
* @param grpcOptions the http client options
70+
* @param httpOptions the http client options
71+
* @return the created client
72+
*/
73+
static GrpcClient client(Vertx vertx, GrpcClientOptions grpcOptions, HttpClientOptions httpOptions) {
74+
return new GrpcClientImpl(vertx, grpcOptions, httpOptions);
75+
}
76+
5577
/**
5678
* Create a client with the specified {@code options}.
5779
*
@@ -60,7 +82,7 @@ static GrpcClient client(Vertx vertx) {
6082
* @return the created client
6183
*/
6284
static GrpcClient client(Vertx vertx, HttpClientOptions options) {
63-
return new GrpcClientImpl(vertx, options);
85+
return new GrpcClientImpl(vertx, new GrpcClientOptions(), options);
6486
}
6587

6688
/**
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright (c) 2011-2024 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.grpc.client;
12+
13+
import io.vertx.codegen.annotations.DataObject;
14+
15+
import java.util.Objects;
16+
import java.util.concurrent.TimeUnit;
17+
18+
/**
19+
* Options configuring a gRPC client.
20+
*/
21+
@DataObject
22+
public class GrpcClientOptions {
23+
24+
/**
25+
* The default value for automatic deadline schedule = {@code false}.
26+
*/
27+
public static final boolean DEFAULT_SCHEDULE_DEADLINE_AUTOMATICALLY = false;
28+
29+
/**
30+
* The default value of the timeout = {@code 0} (no timeout).
31+
*/
32+
public static final int DEFAULT_TIMEOUT = 0;
33+
34+
/**
35+
* The default value of the timeout unit = {@link TimeUnit#SECONDS}.
36+
*/
37+
public static final TimeUnit DEFAULT_TIMEOUT_UNIT = TimeUnit.SECONDS;
38+
39+
private boolean scheduleDeadlineAutomatically;
40+
private int timeout;
41+
private TimeUnit timeoutUnit;
42+
43+
/**
44+
* Default constructor.
45+
*/
46+
public GrpcClientOptions() {
47+
scheduleDeadlineAutomatically = DEFAULT_SCHEDULE_DEADLINE_AUTOMATICALLY;
48+
timeout = DEFAULT_TIMEOUT;
49+
timeoutUnit = DEFAULT_TIMEOUT_UNIT;
50+
}
51+
52+
/**
53+
* Copy constructor.
54+
*
55+
* @param other the options to copy
56+
*/
57+
public GrpcClientOptions(GrpcClientOptions other) {
58+
scheduleDeadlineAutomatically = other.scheduleDeadlineAutomatically;
59+
timeout = other.timeout;
60+
timeoutUnit = other.timeoutUnit;
61+
}
62+
63+
/**
64+
* @return whether the client will automatically schedule a deadline when a request carrying a timeout is sent.
65+
*/
66+
public boolean getScheduleDeadlineAutomatically() {
67+
return scheduleDeadlineAutomatically;
68+
}
69+
70+
/**
71+
* <p>Set whether a deadline is automatically scheduled when a request carrying a timeout (either set explicitly or through this
72+
* options instance) is sent.</p>
73+
*
74+
* <ul>
75+
* <li>When the automatic deadline is set and a request carrying a timeout is sent, a deadline (timer) is created to cancel the request
76+
* when the response has not been timely received. The deadline can be obtained with {@link GrpcClientRequest#deadline()}.</li>
77+
* <li>When the deadline is not set and a request carrying a timeout is sent, the timeout is sent to the server and it remains the
78+
* responsibility of the caller to eventually cancel the request. Note: the server might cancel the request as well when its local deadline is met.</li>
79+
* </ul>
80+
*
81+
* @param handleDeadlineAutomatically whether to automatically set
82+
* @return a reference to this, so the API can be used fluently
83+
*/
84+
public GrpcClientOptions setScheduleDeadlineAutomatically(boolean handleDeadlineAutomatically) {
85+
this.scheduleDeadlineAutomatically = handleDeadlineAutomatically;
86+
return this;
87+
}
88+
89+
/**
90+
* Return the default timeout set when sending gRPC requests, the initial value is {@code 0} which does not
91+
* send a timeout.
92+
*
93+
* @return the default timeout.
94+
*/
95+
public int getTimeout() {
96+
return timeout;
97+
}
98+
99+
/**
100+
* Set the default timeout set when sending gRPC requests, this value should be set along with {@link #setTimeoutUnit(TimeUnit)}.
101+
*
102+
* @param timeout the timeout value
103+
* @return a reference to this, so the API can be used fluently
104+
*/
105+
public GrpcClientOptions setTimeout(int timeout) {
106+
if (timeout < 0L) {
107+
throw new IllegalArgumentException("Timeout value must be >= 0");
108+
}
109+
this.timeout = timeout;
110+
return this;
111+
}
112+
113+
/**
114+
* @return the unit of time of the default timeout.
115+
*/
116+
public TimeUnit getTimeoutUnit() {
117+
return timeoutUnit;
118+
}
119+
120+
/**
121+
* Set the unit of time of the default timeout value.
122+
*
123+
* @param timeoutUnit the unit of time
124+
* @return a reference to this, so the API can be used fluently
125+
*/
126+
public GrpcClientOptions setTimeoutUnit(TimeUnit timeoutUnit) {
127+
this.timeoutUnit = Objects.requireNonNull(timeoutUnit);
128+
return this;
129+
}
130+
}

vertx-grpc-client/src/main/java/io/vertx/grpc/client/GrpcClientRequest.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,24 @@ public interface GrpcClientRequest<Req, Resp> extends GrpcWriteStream<Req> {
9494
@Override
9595
GrpcClientRequest<Req, Resp> drainHandler(@Nullable Handler<Void> handler);
9696

97+
/**
98+
* <p>Set a {@code grpc-timeout} header to be sent to the server to indicate the client expects a response with
99+
* a timeout.</p>
100+
*
101+
* <p>When the request handle deadline a timer will be set when sending the request to cancel the request when the response
102+
* has not been received in time.</p>
103+
*
104+
* @param timeout
105+
* @param unit
106+
* @return
107+
*/
97108
@Fluent
98109
GrpcClientRequest<Req, Resp> timeout(long timeout, TimeUnit unit);
99110

100111
/**
101-
* Schedule a deadline when sending this request
112+
* @return the request deadline or {@code null} when no deadline has been scheduled
102113
*/
103-
Timer scheduleDeadline();
114+
Timer deadline();
104115

105116
/**
106117
* Sets the amount of time after which, if the request does not return any data within the timeout period,

vertx-grpc-client/src/main/java/io/vertx/grpc/client/VertxClientCall.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,7 @@ public void start(Listener<ResponseT> responseListener, Metadata headers) {
7979
if (deadline != null) {
8080
long timeout = deadline.timeRemaining(TimeUnit.MILLISECONDS);
8181
request.timeout(timeout, TimeUnit.MILLISECONDS);
82-
sf = deadline.runOnExpiration(new Runnable() {
83-
@Override
84-
public void run() {
85-
request.cancel();
86-
}
87-
}, new VertxScheduledExecutorService(((GrpcClientRequestImpl)request).context()));
82+
sf = deadline.runOnExpiration(() -> request.cancel(), new VertxScheduledExecutorService(((GrpcClientRequestImpl)request).context()));
8883
} else {
8984
sf = null;
9085
}

0 commit comments

Comments
 (0)