Skip to content

Commit ae614b3

Browse files
authored
pubsub: add Publisher.awaitTermination (#3688)
[Newer gRPC versions](https://github.com/grpc/grpc-java/releases/tag/v1.12.0) seem to check that we call this method. Currently shutdown waits for all messages to publish and return before shutting anything down, so awaitTermination likely won't do anything meaningful. In the future, we should make shutdown return promptly and use awaitTermination to wait for messages. I reported this at #3687. Fixes #3648.
1 parent 739d519 commit ae614b3

File tree

7 files changed

+51
-28
lines changed

7 files changed

+51
-28
lines changed

google-cloud-clients/google-cloud-pubsub/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ try {
119119
} finally {
120120
if (publisher != null) {
121121
publisher.shutdown();
122+
publisher.awaitTermination(1, TimeUnit.MINUTES);
122123
}
123124
}
124125
```

google-cloud-clients/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Publisher.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@
2727
import com.google.api.gax.core.ExecutorProvider;
2828
import com.google.api.gax.core.FixedExecutorProvider;
2929
import com.google.api.gax.core.InstantiatingExecutorProvider;
30-
import com.google.api.gax.grpc.GrpcStatusCode;
3130
import com.google.api.gax.retrying.RetrySettings;
32-
import com.google.api.gax.rpc.ApiException;
33-
import com.google.api.gax.rpc.ApiExceptionFactory;
3431
import com.google.api.gax.rpc.HeaderProvider;
3532
import com.google.api.gax.rpc.NoHeaderProvider;
3633
import com.google.api.gax.rpc.StatusCode;
@@ -46,7 +43,6 @@
4643
import com.google.pubsub.v1.PubsubMessage;
4744
import com.google.pubsub.v1.TopicName;
4845
import com.google.pubsub.v1.TopicNames;
49-
import io.grpc.Status;
5046
import java.io.IOException;
5147
import java.util.Collections;
5248
import java.util.Iterator;
@@ -424,6 +420,16 @@ public void shutdown() throws Exception {
424420
publisherStub.shutdown();
425421
}
426422

423+
/**
424+
* Wait for all work has completed execution after a {@link #shutdown()} request, or the timeout
425+
* occurs, or the current thread is interrupted.
426+
*
427+
* <p>Call this method to make sure all resources are freed properly.
428+
*/
429+
public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException {
430+
return publisherStub.awaitTermination(duration, unit);
431+
}
432+
427433
private boolean hasBatchingBytes() {
428434
return getMaxBatchBytes() > 0;
429435
}
@@ -443,6 +449,7 @@ private boolean hasBatchingBytes() {
443449
* } finally {
444450
* // When finished with the publisher, make sure to shutdown to free up resources.
445451
* publisher.shutdown();
452+
* publisher.awaitTermination(1, TimeUnit.MINUTES);
446453
* }
447454
* }</pre>
448455
*/
@@ -463,6 +470,7 @@ public static Builder newBuilder(TopicName topicName) {
463470
* } finally {
464471
* // When finished with the publisher, make sure to shutdown to free up resources.
465472
* publisher.shutdown();
473+
* publisher.awaitTermination(1, TimeUnit.MINUTES);
466474
* }
467475
* }</pre>
468476
*/

google-cloud-clients/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/it/ITPubSubTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.cloud.pubsub.it;
1818

19+
import static com.google.common.truth.Truth.assertThat;
20+
1921
import com.google.auto.value.AutoValue;
2022
import com.google.cloud.ServiceOptions;
2123
import com.google.cloud.pubsub.v1.AckReplyConsumer;
@@ -32,20 +34,17 @@
3234
import com.google.pubsub.v1.ProjectTopicName;
3335
import com.google.pubsub.v1.PubsubMessage;
3436
import com.google.pubsub.v1.PushConfig;
35-
import org.junit.AfterClass;
36-
import org.junit.BeforeClass;
37-
import org.junit.Rule;
38-
import org.junit.Test;
39-
import org.junit.rules.Timeout;
40-
4137
import java.util.Collections;
4238
import java.util.List;
4339
import java.util.UUID;
4440
import java.util.concurrent.BlockingQueue;
4541
import java.util.concurrent.LinkedBlockingQueue;
4642
import java.util.concurrent.TimeUnit;
47-
48-
import static com.google.common.truth.Truth.assertThat;
43+
import org.junit.AfterClass;
44+
import org.junit.BeforeClass;
45+
import org.junit.Rule;
46+
import org.junit.Test;
47+
import org.junit.rules.Timeout;
4948

5049
public class ITPubSubTest {
5150

@@ -147,6 +146,7 @@ public void failed(Subscriber.State from, Throwable failure) {
147146
.publish(PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8("msg2")).build())
148147
.get();
149148
publisher.shutdown();
149+
publisher.awaitTermination(1, TimeUnit.MINUTES);
150150

151151
// Ack the first message.
152152
MessageAndConsumer toAck = pollQueue(receiveQueue);

google-cloud-clients/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/PublisherImplTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import io.grpc.StatusException;
4343
import io.grpc.inprocess.InProcessServerBuilder;
4444
import java.util.concurrent.ExecutionException;
45+
import java.util.concurrent.TimeUnit;
4546
import org.junit.After;
4647
import org.junit.Before;
4748
import org.junit.Test;
@@ -114,6 +115,7 @@ public void testPublishByDuration() throws Exception {
114115

115116
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().get(0).getMessagesCount());
116117
publisher.shutdown();
118+
publisher.awaitTermination(1, TimeUnit.MINUTES);
117119
}
118120

119121
@Test
@@ -152,6 +154,7 @@ public void testPublishByNumBatchedMessages() throws Exception {
152154
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().get(0).getMessagesCount());
153155
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().get(1).getMessagesCount());
154156
publisher.shutdown();
157+
publisher.awaitTermination(1, TimeUnit.MINUTES);
155158
}
156159

157160
@Test
@@ -186,6 +189,7 @@ public void testSinglePublishByNumBytes() throws Exception {
186189

187190
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().size());
188191
publisher.shutdown();
192+
publisher.awaitTermination(1, TimeUnit.MINUTES);
189193
}
190194

191195
@Test
@@ -228,6 +232,7 @@ public void testPublishMixedSizeAndDuration() throws Exception {
228232
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().get(0).getMessagesCount());
229233
assertEquals(1, testPublisherServiceImpl.getCapturedRequests().get(1).getMessagesCount());
230234
publisher.shutdown();
235+
publisher.awaitTermination(1, TimeUnit.MINUTES);
231236
}
232237

233238
private ApiFuture<String> sendTestMessage(Publisher publisher, String data) {
@@ -278,6 +283,7 @@ public void testPublishFailureRetries() throws Exception {
278283

279284
assertEquals(2, testPublisherServiceImpl.getCapturedRequests().size());
280285
publisher.shutdown();
286+
publisher.awaitTermination(1, TimeUnit.MINUTES);
281287
}
282288

283289
@Test(expected = ExecutionException.class)
@@ -302,6 +308,7 @@ public void testPublishFailureRetries_retriesDisabled() throws Exception {
302308
} finally {
303309
assertSame(testPublisherServiceImpl.getCapturedRequests().size(), 1);
304310
publisher.shutdown();
311+
publisher.awaitTermination(1, TimeUnit.MINUTES);
305312
}
306313
}
307314

@@ -328,6 +335,7 @@ public void testPublishFailureRetries_maxRetriesSetup() throws Exception {
328335

329336
assertEquals(3, testPublisherServiceImpl.getCapturedRequests().size());
330337
publisher.shutdown();
338+
publisher.awaitTermination(1, TimeUnit.MINUTES);
331339
}
332340

333341
@Test
@@ -353,6 +361,7 @@ public void testPublishFailureRetries_maxRetriesSetUnlimited() throws Exception
353361

354362
assertEquals(3, testPublisherServiceImpl.getCapturedRequests().size());
355363
publisher.shutdown();
364+
publisher.awaitTermination(1, TimeUnit.MINUTES);
356365
}
357366

358367
@Test(expected = ExecutionException.class)
@@ -381,6 +390,7 @@ public void testPublishFailureRetries_nonRetryableFailsImmediately() throws Exce
381390
} finally {
382391
assertTrue(testPublisherServiceImpl.getCapturedRequests().size() >= 1);
383392
publisher.shutdown();
393+
publisher.awaitTermination(1, TimeUnit.MINUTES);
384394
}
385395
}
386396

@@ -403,6 +413,7 @@ public void testPublisherGetters() throws Exception {
403413
assertEquals(Duration.ofMillis(11), publisher.getBatchingSettings().getDelayThreshold());
404414
assertEquals(12, (long) publisher.getBatchingSettings().getElementCountThreshold());
405415
publisher.shutdown();
416+
publisher.awaitTermination(1, TimeUnit.MINUTES);
406417
}
407418

408419
@Test

google-cloud-examples/src/main/java/com/google/cloud/examples/pubsub/snippets/CreateTopicAndPublishMessages.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
import com.google.protobuf.ByteString;
2626
import com.google.pubsub.v1.ProjectTopicName;
2727
import com.google.pubsub.v1.PubsubMessage;
28-
2928
import java.util.ArrayList;
3029
import java.util.Arrays;
3130
import java.util.List;
31+
import java.util.concurrent.TimeUnit;
3232

3333
/**
3434
* A snippet for Google Cloud Pub/Sub showing how to create a Pub/Sub topic and asynchronously
@@ -75,6 +75,7 @@ public static void publishMessages() throws Exception {
7575
if (publisher != null) {
7676
// When finished with the publisher, shutdown to free up resources.
7777
publisher.shutdown();
78+
publisher.awaitTermination(1, TimeUnit.MINUTES);
7879
}
7980
}
8081
// [END pubsub_publish]
@@ -123,11 +124,12 @@ public void onSuccess(String messageId) {
123124
if (publisher != null) {
124125
// When finished with the publisher, shutdown to free up resources.
125126
publisher.shutdown();
127+
publisher.awaitTermination(1, TimeUnit.MINUTES);
126128
}
127129
}
128130
// [END pubsub_publish_error_handler]
129131
}
130-
132+
131133
public static void main(String... args) throws Exception {
132134
createTopic();
133135
publishMessages();

google-cloud-examples/src/main/java/com/google/cloud/examples/pubsub/snippets/PublisherSnippets.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
import com.google.protobuf.ByteString;
3636
import com.google.pubsub.v1.ProjectTopicName;
3737
import com.google.pubsub.v1.PubsubMessage;
38-
import org.threeten.bp.Duration;
39-
4038
import java.io.FileInputStream;
39+
import java.util.concurrent.TimeUnit;
40+
import org.threeten.bp.Duration;
4141

4242
/** This class contains snippets for the {@link Publisher} interface. */
4343
public class PublisherSnippets {
@@ -78,6 +78,7 @@ public static void newBuilder(String projectId, String topicId) throws Exception
7878
} finally {
7979
// When finished with the publisher, make sure to shutdown to free up resources.
8080
publisher.shutdown();
81+
publisher.awaitTermination(1, TimeUnit.MINUTES);
8182
}
8283
}
8384

@@ -108,8 +109,8 @@ public Publisher getPublisherWithCustomRetrySettings(ProjectTopicName topicName)
108109
Duration retryDelay = Duration.ofMillis(100); // default : 1 ms
109110
double retryDelayMultiplier = 2.0; // back off for repeated failures
110111
Duration maxRetryDelay = Duration.ofSeconds(5); // default : 10 seconds
111-
Duration totalTimeout = Duration.ofSeconds(1); // default: 0
112-
Duration initialRpcTimeout = Duration.ofSeconds(1); // default: 0
112+
Duration totalTimeout = Duration.ofSeconds(1); // default: 0
113+
Duration initialRpcTimeout = Duration.ofSeconds(1); // default: 0
113114
Duration maxRpcTimeout = Duration.ofSeconds(10); // default: 0
114115

115116
RetrySettings retrySettings = RetrySettings.newBuilder()

google-cloud-examples/src/test/java/com/google/cloud/examples/pubsub/snippets/ITPubSubSnippets.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package com.google.cloud.examples.pubsub.snippets;
1818

19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotNull;
21+
1922
import com.google.api.core.ApiFuture;
2023
import com.google.api.core.ApiFutureCallback;
2124
import com.google.api.core.ApiFutures;
@@ -24,27 +27,22 @@
2427
import com.google.cloud.pubsub.v1.Publisher;
2528
import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
2629
import com.google.cloud.pubsub.v1.TopicAdminClient;
27-
import com.google.common.util.concurrent.MoreExecutors;
2830
import com.google.pubsub.v1.ProjectSubscriptionName;
2931
import com.google.pubsub.v1.ProjectTopicName;
3032
import com.google.pubsub.v1.PubsubMessage;
3133
import com.google.pubsub.v1.PushConfig;
3234
import com.google.pubsub.v1.ReceivedMessage;
33-
import org.junit.After;
34-
import org.junit.Before;
35-
import org.junit.Rule;
36-
import org.junit.Test;
37-
import org.junit.rules.Timeout;
38-
3935
import java.util.ArrayList;
4036
import java.util.List;
4137
import java.util.UUID;
4238
import java.util.concurrent.ArrayBlockingQueue;
4339
import java.util.concurrent.BlockingQueue;
4440
import java.util.concurrent.TimeUnit;
45-
46-
import static org.junit.Assert.assertEquals;
47-
import static org.junit.Assert.assertNotNull;
41+
import org.junit.After;
42+
import org.junit.Before;
43+
import org.junit.Rule;
44+
import org.junit.Test;
45+
import org.junit.rules.Timeout;
4846

4947
public class ITPubSubSnippets {
5048

@@ -98,6 +96,7 @@ public void onFailure(Throwable t) {
9896
} finally {
9997
if (publisher != null) {
10098
publisher.shutdown();
99+
publisher.awaitTermination(1, TimeUnit.MINUTES);
101100
}
102101
}
103102

@@ -144,6 +143,7 @@ public void testPublisherSyncSubscriber() throws Exception {
144143
} finally {
145144
if (publisher != null) {
146145
publisher.shutdown();
146+
publisher.awaitTermination(1, TimeUnit.MINUTES);
147147
}
148148
}
149149

0 commit comments

Comments
 (0)