Skip to content

Commit 4f29420

Browse files
committed
feat/add-async-channel-ping
Change-Id: I3e390b6f7a6c9beaee52d74f37ef557629af7759
1 parent 19a5de2 commit 4f29420

2 files changed

Lines changed: 91 additions & 34 deletions

File tree

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableChannelPrimer.java

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -96,43 +96,12 @@ public void primeChannel(ManagedChannel managedChannel) {
9696
}
9797

9898
private void primeChannelUnsafe(ManagedChannel managedChannel) throws IOException {
99-
sendPrimeRequests(managedChannel);
99+
sendPrimeRequestsBlocking(managedChannel);
100100
}
101101

102-
private void sendPrimeRequests(ManagedChannel managedChannel) {
102+
private void sendPrimeRequestsBlocking(ManagedChannel managedChannel) {
103103
try {
104-
ClientCall<PingAndWarmRequest, PingAndWarmResponse> clientCall =
105-
managedChannel.newCall(
106-
BigtableGrpc.getPingAndWarmMethod(),
107-
CallOptions.DEFAULT
108-
.withCallCredentials(callCredentials)
109-
.withDeadline(Deadline.after(1, TimeUnit.MINUTES)));
110-
111-
SettableApiFuture<PingAndWarmResponse> future = SettableApiFuture.create();
112-
clientCall.start(
113-
new ClientCall.Listener<PingAndWarmResponse>() {
114-
PingAndWarmResponse response;
115-
116-
@Override
117-
public void onMessage(PingAndWarmResponse message) {
118-
response = message;
119-
}
120-
121-
@Override
122-
public void onClose(Status status, Metadata trailers) {
123-
if (status.isOk()) {
124-
future.set(response);
125-
} else {
126-
future.setException(status.asException());
127-
}
128-
}
129-
},
130-
createMetadata(headers, request));
131-
clientCall.sendMessage(request);
132-
clientCall.halfClose();
133-
clientCall.request(Integer.MAX_VALUE);
134-
135-
future.get(1, TimeUnit.MINUTES);
104+
sendPrimeRequestsAsync(managedChannel).get(1, TimeUnit.MINUTES);
136105
} catch (Throwable e) {
137106
// TODO: Not sure if we should swallow the error here. We are pre-emptively swapping
138107
// channels if the new
@@ -141,6 +110,59 @@ public void onClose(Status status, Metadata trailers) {
141110
}
142111
}
143112

113+
/**
114+
* Asynchronously sends a PingAndWarm request.
115+
*
116+
* @param managedChannel The channel to send the request on.
117+
* @return A ListenableFuture that will be completed with the PingAndWarmResponse or an exception.
118+
*/
119+
public SettableApiFuture<PingAndWarmResponse> sendPrimeRequestsAsync(
120+
ManagedChannel managedChannel) {
121+
ClientCall<PingAndWarmRequest, PingAndWarmResponse> clientCall =
122+
managedChannel.newCall(
123+
BigtableGrpc.getPingAndWarmMethod(),
124+
CallOptions.DEFAULT
125+
.withCallCredentials(callCredentials)
126+
.withDeadline(Deadline.after(1, TimeUnit.MINUTES)));
127+
128+
SettableApiFuture<PingAndWarmResponse> future = SettableApiFuture.create();
129+
clientCall.start(
130+
new ClientCall.Listener<PingAndWarmResponse>() {
131+
private PingAndWarmResponse response;
132+
133+
@Override
134+
public void onMessage(PingAndWarmResponse message) {
135+
response = message;
136+
}
137+
138+
@Override
139+
public void onClose(Status status, Metadata trailers) {
140+
if (status.isOk()) {
141+
future.set(response);
142+
} else {
143+
// Propagate the gRPC error to the future.
144+
future.setException(status.asException(trailers));
145+
}
146+
}
147+
},
148+
createMetadata(headers, request));
149+
150+
try {
151+
// Send the request message.
152+
clientCall.sendMessage(request);
153+
// Signal that no more messages will be sent.
154+
clientCall.halfClose();
155+
// Request the response from the server.
156+
clientCall.request(Integer.MAX_VALUE);
157+
} catch (Throwable t) {
158+
// If sending fails, cancel the call and notify the future.
159+
clientCall.cancel("Failed to send priming request", t);
160+
future.setException(t);
161+
}
162+
163+
return future;
164+
}
165+
144166
private static Metadata createMetadata(Map<String, String> headers, PingAndWarmRequest request) {
145167
Metadata metadata = new Metadata();
146168

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/stub/BigtableChannelPrimerTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.google.common.truth.Truth.assertThat;
1919

2020
import com.google.api.core.ApiFunction;
21+
import com.google.api.core.SettableApiFuture;
2122
import com.google.auth.oauth2.AccessToken;
2223
import com.google.auth.oauth2.OAuth2Credentials;
2324
import com.google.bigtable.v2.BigtableGrpc.BigtableImplBase;
@@ -39,6 +40,8 @@
3940
import java.io.IOException;
4041
import java.util.Queue;
4142
import java.util.concurrent.ConcurrentLinkedQueue;
43+
import java.util.concurrent.ExecutionException;
44+
import java.util.concurrent.TimeUnit;
4245
import java.util.logging.Handler;
4346
import java.util.logging.LogRecord;
4447
import java.util.logging.Logger;
@@ -166,6 +169,38 @@ public void testHeadersAreSent() {
166169
}
167170
}
168171

172+
// New test for the async success path
173+
@Test
174+
public void testAsyncSuccess() throws Exception {
175+
SettableApiFuture<PingAndWarmResponse> future = primer.sendPrimeRequestsAsync(channel);
176+
177+
PingAndWarmResponse response = future.get(1, TimeUnit.SECONDS);
178+
assertThat(response).isNotNull();
179+
assertThat(future.isDone()).isTrue();
180+
}
181+
182+
// New test for the async failure path
183+
@Test
184+
public void testAsyncFailure() {
185+
// Configure the server to return a gRPC error
186+
fakeService.pingAndWarmCallback =
187+
new ApiFunction<PingAndWarmRequest, PingAndWarmResponse>() {
188+
@Override
189+
public PingAndWarmResponse apply(PingAndWarmRequest pingAndWarmRequest) {
190+
throw new StatusRuntimeException(Status.UNAVAILABLE);
191+
}
192+
};
193+
194+
SettableApiFuture<PingAndWarmResponse> future = primer.sendPrimeRequestsAsync(channel);
195+
196+
try {
197+
future.get(1, TimeUnit.SECONDS);
198+
} catch (Exception e) {
199+
// Assert that the future completes with an ExecutionException
200+
assertThat(e).isInstanceOf(ExecutionException.class);
201+
}
202+
}
203+
169204
private static class MetadataInterceptor implements ServerInterceptor {
170205
ConcurrentLinkedQueue<Metadata> metadataList = new ConcurrentLinkedQueue<>();
171206

0 commit comments

Comments
 (0)