Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

Commit 68761a7

Browse files
authored
feat(operations): Add WaitOperation API surface [gax-java] (#1284)
* fix(lro): Add Operation name to get, list requests * fix: add name header to {Cancel,Delete}Operation * feat(operations): Add WaitOperation API surface * fix: update OperationsClient comments * fix: Add override annotations to GrpcOperationsStub * fix: update comment in OperationsClient * fix: comment cleanup * fix: MockOperationsImpl error message
1 parent 348f136 commit 68761a7

File tree

7 files changed

+196
-2
lines changed

7 files changed

+196
-2
lines changed

‎gax-grpc/src/main/java/com/google/longrunning/OperationsClient.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public final Operation getOperation(String name) {
192192
* }
193193
* </code></pre>
194194
*
195-
* @param request The request object containing all of the parameters for the API call.
195+
* @param request the request object containing all of the parameters for the API call
196196
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
197197
*/
198198
private final Operation getOperation(GetOperationRequest request) {
@@ -502,6 +502,61 @@ public final UnaryCallable<DeleteOperationRequest, Empty> deleteOperationCallabl
502502
return stub.deleteOperationCallable();
503503
}
504504

505+
/**
506+
* Waits until the specified long-running operation is done or reaches at most a specified
507+
* timeout, returning the latest state. If the operation is already done, the latest state is
508+
* immediately returned. If the timeout specified is greater than the default HTTP/RPC timeout,
509+
* the HTTP/RPC timeout is used. If the server does not support this method, it returns
510+
* `google.rpc.Code.UNIMPLEMENTED`. Note that this method is on a best-effort basis. It may return
511+
* the latest state before the specified timeout (including immediately), meaning even an
512+
* immediate response is no guarantee that the operation is done.
513+
*
514+
* <p>Sample code:
515+
*
516+
* <pre><code>
517+
* try (OperationsClient operationsClient = OperationsClient.create()) {
518+
* String name = "";
519+
* WaitOperationRequest request = WaitOperationRequest.newBuilder()
520+
* .setName(name)
521+
* .setTimeout(Duration.ofMillis(100))
522+
* .build();
523+
* Operation response = operationsClient.waitOperation(request);
524+
* }
525+
* </code></pre>
526+
*
527+
* @param request the request object containing all of the parameters for the API call.
528+
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
529+
*/
530+
public final Operation waitOperation(WaitOperationRequest request) {
531+
return waitOperationCallable().call(request);
532+
}
533+
534+
/**
535+
* Waits until the specified long-running operation is done or reaches at most a specified
536+
* timeout, returning the latest state. If the operation is already done, the latest state is
537+
* immediately returned. If the timeout specified is greater than the default HTTP/RPC timeout,
538+
* the HTTP/RPC timeout is used. If the server does not support this method, it returns
539+
* `google.rpc.Code.UNIMPLEMENTED`. Note that this method is on a best-effort basis. It may return
540+
* the latest state before the specified timeout (including immediately), meaning even an
541+
* immediate response is no guarantee that the operation is done.
542+
*
543+
* <p>Sample code:
544+
*
545+
* <pre><code>
546+
* try (OperationsClient operationsClient = OperationsClient.create()) {
547+
* String name = "";
548+
* WaitOperationRequest request = WaitOperationRequest.newBuilder()
549+
* .setName(name)
550+
* .setTimeout(Duration.ofMillis(100))
551+
* .build();
552+
* ApiFuture&lt;Operation&gt; future = operationsClient.waitOperationCallable().futureCall(request);
553+
* }
554+
* </code></pre>
555+
*/
556+
public final UnaryCallable<WaitOperationRequest, Operation> waitOperationCallable() {
557+
return stub.waitOperationCallable();
558+
}
559+
505560
@Override
506561
public final void close() {
507562
stub.close();

‎gax-grpc/src/main/java/com/google/longrunning/OperationsSettings.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ public UnaryCallSettings<DeleteOperationRequest, Empty> deleteOperationSettings(
6868
return ((OperationsStubSettings) getStubSettings()).deleteOperationSettings();
6969
}
7070

71+
/** Returns the object with the settings used for calls to waitOperation. */
72+
public UnaryCallSettings<WaitOperationRequest, Operation> waitOperationSettings() {
73+
return ((OperationsStubSettings) getStubSettings()).waitOperationSettings();
74+
}
75+
7176
public static final OperationsSettings create(OperationsStubSettings stub) throws IOException {
7277
return new OperationsSettings.Builder(stub.toBuilder()).build();
7378
}
@@ -166,6 +171,11 @@ public UnaryCallSettings.Builder<DeleteOperationRequest, Empty> deleteOperationS
166171
return getStubSettingsBuilder().deleteOperationSettings();
167172
}
168173

174+
/** Returns the builder for the settings used for calls to deleteOperation. */
175+
public UnaryCallSettings.Builder<WaitOperationRequest, Operation> waitOperationSettings() {
176+
return getStubSettingsBuilder().waitOperationSettings();
177+
}
178+
169179
@Override
170180
public OperationsSettings build() throws IOException {
171181
return new OperationsSettings(this);

‎gax-grpc/src/main/java/com/google/longrunning/stub/GrpcOperationsStub.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.google.longrunning.ListOperationsRequest;
4747
import com.google.longrunning.ListOperationsResponse;
4848
import com.google.longrunning.Operation;
49+
import com.google.longrunning.WaitOperationRequest;
4950
import com.google.protobuf.Empty;
5051
import io.grpc.MethodDescriptor;
5152
import io.grpc.protobuf.ProtoUtils;
@@ -97,6 +98,15 @@ public class GrpcOperationsStub extends OperationsStub {
9798
ProtoUtils.marshaller(DeleteOperationRequest.getDefaultInstance()))
9899
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
99100
.build();
101+
private static final MethodDescriptor<WaitOperationRequest, Operation>
102+
waitOperationMethodDescriptor =
103+
MethodDescriptor.<WaitOperationRequest, Operation>newBuilder()
104+
.setType(MethodDescriptor.MethodType.UNARY)
105+
.setFullMethodName("google.longrunning.Operations/WaitOperation")
106+
.setRequestMarshaller(
107+
ProtoUtils.marshaller(WaitOperationRequest.getDefaultInstance()))
108+
.setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance()))
109+
.build();
100110

101111
private final BackgroundResource backgroundResources;
102112

@@ -106,6 +116,7 @@ public class GrpcOperationsStub extends OperationsStub {
106116
listOperationsPagedCallable;
107117
private final UnaryCallable<CancelOperationRequest, Empty> cancelOperationCallable;
108118
private final UnaryCallable<DeleteOperationRequest, Empty> deleteOperationCallable;
119+
private final UnaryCallable<WaitOperationRequest, Operation> waitOperationCallable;
109120

110121
private final GrpcStubCallableFactory callableFactory;
111122

@@ -199,6 +210,19 @@ public Map<String, String> extract(DeleteOperationRequest request) {
199210
}
200211
})
201212
.build();
213+
GrpcCallSettings<WaitOperationRequest, Operation> waitOperationTransportSettings =
214+
GrpcCallSettings.<WaitOperationRequest, Operation>newBuilder()
215+
.setMethodDescriptor(waitOperationMethodDescriptor)
216+
.setParamsExtractor(
217+
new RequestParamsExtractor<WaitOperationRequest>() {
218+
@Override
219+
public Map<String, String> extract(WaitOperationRequest request) {
220+
ImmutableMap.Builder<String, String> params = ImmutableMap.builder();
221+
params.put("name", String.valueOf(request.getName()));
222+
return params.build();
223+
}
224+
})
225+
.build();
202226

203227
this.getOperationCallable =
204228
callableFactory.createUnaryCallable(
@@ -215,31 +239,44 @@ public Map<String, String> extract(DeleteOperationRequest request) {
215239
this.deleteOperationCallable =
216240
callableFactory.createUnaryCallable(
217241
deleteOperationTransportSettings, settings.deleteOperationSettings(), clientContext);
242+
this.waitOperationCallable =
243+
callableFactory.createUnaryCallable(
244+
waitOperationTransportSettings, settings.waitOperationSettings(), clientContext);
218245

219246
backgroundResources = new BackgroundResourceAggregation(clientContext.getBackgroundResources());
220247
}
221248

249+
@Override
222250
public UnaryCallable<GetOperationRequest, Operation> getOperationCallable() {
223251
return getOperationCallable;
224252
}
225253

254+
@Override
226255
public UnaryCallable<ListOperationsRequest, ListOperationsPagedResponse>
227256
listOperationsPagedCallable() {
228257
return listOperationsPagedCallable;
229258
}
230259

260+
@Override
231261
public UnaryCallable<ListOperationsRequest, ListOperationsResponse> listOperationsCallable() {
232262
return listOperationsCallable;
233263
}
234264

265+
@Override
235266
public UnaryCallable<CancelOperationRequest, Empty> cancelOperationCallable() {
236267
return cancelOperationCallable;
237268
}
238269

270+
@Override
239271
public UnaryCallable<DeleteOperationRequest, Empty> deleteOperationCallable() {
240272
return deleteOperationCallable;
241273
}
242274

275+
@Override
276+
public UnaryCallable<WaitOperationRequest, Operation> waitOperationCallable() {
277+
return waitOperationCallable;
278+
}
279+
243280
@Override
244281
public final void close() {
245282
shutdown();

‎gax-grpc/src/main/java/com/google/longrunning/stub/OperationsStub.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.google.longrunning.ListOperationsRequest;
4141
import com.google.longrunning.ListOperationsResponse;
4242
import com.google.longrunning.Operation;
43+
import com.google.longrunning.WaitOperationRequest;
4344
import com.google.protobuf.Empty;
4445

4546
/**
@@ -71,6 +72,10 @@ public UnaryCallable<DeleteOperationRequest, Empty> deleteOperationCallable() {
7172
throw new UnsupportedOperationException("Not implemented: deleteOperationCallable()");
7273
}
7374

75+
public UnaryCallable<WaitOperationRequest, Operation> waitOperationCallable() {
76+
throw new UnsupportedOperationException("Not implemented: waitOperationCallable()");
77+
}
78+
7479
@Override
7580
public abstract void close();
7681
}

‎gax-grpc/src/main/java/com/google/longrunning/stub/OperationsStubSettings.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.google.longrunning.ListOperationsRequest;
6262
import com.google.longrunning.ListOperationsResponse;
6363
import com.google.longrunning.Operation;
64+
import com.google.longrunning.WaitOperationRequest;
6465
import com.google.protobuf.Empty;
6566
import java.io.IOException;
6667
import org.threeten.bp.Duration;
@@ -75,6 +76,7 @@ public class OperationsStubSettings extends StubSettings<OperationsStubSettings>
7576
listOperationsSettings;
7677
private final UnaryCallSettings<CancelOperationRequest, Empty> cancelOperationSettings;
7778
private final UnaryCallSettings<DeleteOperationRequest, Empty> deleteOperationSettings;
79+
private final UnaryCallSettings<WaitOperationRequest, Operation> waitOperationSettings;
7880

7981
/** Returns the object with the settings used for calls to getOperation. */
8082
public UnaryCallSettings<GetOperationRequest, Operation> getOperationSettings() {
@@ -98,6 +100,11 @@ public UnaryCallSettings<DeleteOperationRequest, Empty> deleteOperationSettings(
98100
return deleteOperationSettings;
99101
}
100102

103+
/** Returns the object with the settings used for calls to waitOperation. */
104+
public UnaryCallSettings<WaitOperationRequest, Operation> waitOperationSettings() {
105+
return waitOperationSettings;
106+
}
107+
101108
@BetaApi("A restructuring of stub classes is planned, so this may break in the future")
102109
public OperationsStub createStub() throws IOException {
103110
if (getTransportChannelProvider()
@@ -151,6 +158,7 @@ protected OperationsStubSettings(Builder settingsBuilder) throws IOException {
151158
listOperationsSettings = settingsBuilder.listOperationsSettings().build();
152159
cancelOperationSettings = settingsBuilder.cancelOperationSettings().build();
153160
deleteOperationSettings = settingsBuilder.deleteOperationSettings().build();
161+
waitOperationSettings = settingsBuilder.waitOperationSettings().build();
154162
}
155163

156164
private static final PagedListDescriptor<ListOperationsRequest, ListOperationsResponse, Operation>
@@ -215,6 +223,7 @@ public static class Builder extends StubSettings.Builder<OperationsStubSettings,
215223
listOperationsSettings;
216224
private final UnaryCallSettings.Builder<CancelOperationRequest, Empty> cancelOperationSettings;
217225
private final UnaryCallSettings.Builder<DeleteOperationRequest, Empty> deleteOperationSettings;
226+
private final UnaryCallSettings.Builder<WaitOperationRequest, Operation> waitOperationSettings;
218227

219228
private static final ImmutableMap<String, ImmutableSet<StatusCode.Code>>
220229
RETRYABLE_CODE_DEFINITIONS;
@@ -265,6 +274,8 @@ protected Builder(ClientContext clientContext) {
265274

266275
deleteOperationSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
267276

277+
waitOperationSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
278+
268279
unaryMethodSettingsBuilders =
269280
ImmutableList.<UnaryCallSettings.Builder<?, ?>>of(
270281
getOperationSettings,
@@ -302,6 +313,11 @@ private static Builder initDefaults(Builder builder) {
302313
.setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
303314
.setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default"));
304315

316+
builder
317+
.waitOperationSettings()
318+
.setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("idempotent"))
319+
.setRetrySettings(RETRY_PARAM_DEFINITIONS.get("default"));
320+
305321
return builder;
306322
}
307323

@@ -312,13 +328,15 @@ protected Builder(OperationsStubSettings settings) {
312328
listOperationsSettings = settings.listOperationsSettings.toBuilder();
313329
cancelOperationSettings = settings.cancelOperationSettings.toBuilder();
314330
deleteOperationSettings = settings.deleteOperationSettings.toBuilder();
331+
waitOperationSettings = settings.waitOperationSettings.toBuilder();
315332

316333
unaryMethodSettingsBuilders =
317334
ImmutableList.<UnaryCallSettings.Builder<?, ?>>of(
318335
getOperationSettings,
319336
listOperationsSettings,
320337
cancelOperationSettings,
321-
deleteOperationSettings);
338+
deleteOperationSettings,
339+
waitOperationSettings);
322340
}
323341

324342
/**
@@ -358,6 +376,11 @@ public UnaryCallSettings.Builder<DeleteOperationRequest, Empty> deleteOperationS
358376
return deleteOperationSettings;
359377
}
360378

379+
/** Returns the builder for the settings used for calls to waitOperation. */
380+
public UnaryCallSettings.Builder<WaitOperationRequest, Operation> waitOperationSettings() {
381+
return waitOperationSettings;
382+
}
383+
361384
@Override
362385
public OperationsStubSettings build() throws IOException {
363386
return new OperationsStubSettings(this);

‎gax-grpc/src/test/java/com/google/longrunning/MockOperationsImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,25 @@ public void cancelOperation(
130130
responseObserver.onError(new IllegalArgumentException("Unrecognized response type"));
131131
}
132132
}
133+
134+
@Override
135+
public void waitOperation(
136+
WaitOperationRequest request, StreamObserver<Operation> responseObserver) {
137+
Object response = responses.remove();
138+
if (response instanceof Operation) {
139+
requests.add(request);
140+
responseObserver.onNext((Operation) response);
141+
responseObserver.onCompleted();
142+
} else if (response instanceof Exception) {
143+
responseObserver.onError((Exception) response);
144+
} else {
145+
responseObserver.onError(
146+
new IllegalArgumentException(
147+
String.format(
148+
"Unrecognized response type %s, expected %s or %s",
149+
response.getClass().getName(),
150+
Operation.class.getName(),
151+
Exception.class.getName())));
152+
}
153+
}
133154
}

‎gax-grpc/src/test/java/com/google/longrunning/OperationsClientTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.google.api.gax.rpc.InvalidArgumentException;
3939
import com.google.common.collect.Lists;
4040
import com.google.protobuf.AbstractMessage;
41+
import com.google.protobuf.Duration;
4142
import com.google.protobuf.Empty;
4243
import io.grpc.Status;
4344
import io.grpc.StatusRuntimeException;
@@ -235,4 +236,46 @@ public void deleteOperationExceptionTest() throws Exception {
235236
// Expected exception
236237
}
237238
}
239+
240+
@Test
241+
@SuppressWarnings("all")
242+
public void waitOperationTest() {
243+
String name2 = "name2-1052831874";
244+
boolean done = true;
245+
Operation expectedResponse = Operation.newBuilder().setName(name2).setDone(done).build();
246+
mockOperations.addResponse(expectedResponse);
247+
248+
String name = "name3373707";
249+
Duration timeout = Duration.newBuilder().setSeconds(5).build();
250+
WaitOperationRequest request =
251+
WaitOperationRequest.newBuilder().setName(name).setTimeout(timeout).build();
252+
253+
Operation actualResponse = client.waitOperation(request);
254+
Assert.assertEquals(expectedResponse, actualResponse);
255+
256+
List<AbstractMessage> actualRequests = mockOperations.getRequests();
257+
Assert.assertEquals(1, actualRequests.size());
258+
WaitOperationRequest actualRequest = (WaitOperationRequest) actualRequests.get(0);
259+
260+
Assert.assertEquals(name, actualRequest.getName());
261+
}
262+
263+
@Test
264+
@SuppressWarnings("all")
265+
public void waitOperationExceptionTest() throws Exception {
266+
StatusRuntimeException exception = new StatusRuntimeException(Status.INVALID_ARGUMENT);
267+
mockOperations.addException(exception);
268+
269+
try {
270+
String name = "name3373707";
271+
Duration timeout = Duration.newBuilder().setSeconds(5).build();
272+
WaitOperationRequest request =
273+
WaitOperationRequest.newBuilder().setName(name).setTimeout(timeout).build();
274+
275+
client.waitOperation(request);
276+
Assert.fail("No exception raised");
277+
} catch (InvalidArgumentException e) {
278+
// Expected exception
279+
}
280+
}
238281
}

0 commit comments

Comments
 (0)