From 735660d75a9582dd2402fd77b3a054d1acc5038e Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 26 Aug 2025 13:37:18 -0400 Subject: [PATCH 1/9] chore: Test with Protobuf-Java v4.29.4 --- .kokoro/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.kokoro/build.sh b/.kokoro/build.sh index 41903cda1..96e87d83c 100755 --- a/.kokoro/build.sh +++ b/.kokoro/build.sh @@ -62,6 +62,7 @@ javadoc) integration) mvn -B ${INTEGRATION_TEST_ARGS} \ -ntp \ + -Dprotobuf.version=4.29.4 \ -Penable-integration-tests \ -DtrimStackTrace=false \ -Dclirr.skip=true \ From 842a4fa85c3f5eb5d0b11fc7cc00c33c946f31ea Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Wed, 24 Sep 2025 14:50:26 +0000 Subject: [PATCH 2/9] chore: generate libraries at Wed Sep 24 14:48:29 UTC 2025 --- .github/workflows/update_generation_config.yaml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml index 59e39834d..a7e14bb48 100644 --- a/.github/workflows/update_generation_config.yaml +++ b/.github/workflows/update_generation_config.yaml @@ -26,7 +26,7 @@ jobs: # the branch into which the pull request is merged base_branch: main steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} diff --git a/README.md b/README.md index c9f8d2e12..18d9a442d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.66.0 + 26.68.0 pom import @@ -43,7 +43,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-pubsub - 1.141.2 + 1.141.4 ``` From ea0c8960e0f5c13d4a1f84949402d39096e36581 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Mon, 6 Oct 2025 14:59:54 +0000 Subject: [PATCH 3/9] chore: generate libraries at Mon Oct 6 14:57:46 UTC 2025 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8169e651f..8b9d2beff 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-pubsub - 1.141.4 + 1.141.5 ``` From c2de6951d7c902e66b40a016ed84fdb979ad8447 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Mon, 6 Oct 2025 20:45:50 +0000 Subject: [PATCH 4/9] chore: generate libraries at Mon Oct 6 20:43:54 UTC 2025 --- .github/workflows/update_generation_config.yaml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml index 59e39834d..a7e14bb48 100644 --- a/.github/workflows/update_generation_config.yaml +++ b/.github/workflows/update_generation_config.yaml @@ -26,7 +26,7 @@ jobs: # the branch into which the pull request is merged base_branch: main steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} diff --git a/README.md b/README.md index 8b9d2beff..8af5bb6a5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.68.0 + 26.69.0 pom import From 890fa0d20044ff8b573118cfa95718375a0876b7 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Wed, 8 Oct 2025 03:26:34 +0000 Subject: [PATCH 5/9] chore: generate libraries at Wed Oct 8 03:24:39 UTC 2025 --- .../cloud/pubsub/v1/MessageDispatcher.java | 6 +- .../google/cloud/pubsub/v1/Subscriber.java | 3 +- .../pubsub/v1/SubscriberShutdownSettings.java | 102 ------------------ .../v1/SubscriberShutdownSettingsTest.java | 100 ----------------- 4 files changed, 6 insertions(+), 205 deletions(-) delete mode 100644 google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java delete mode 100644 google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/MessageDispatcher.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/MessageDispatcher.java index 1a6dab2b2..5ed36b9cd 100644 --- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/MessageDispatcher.java +++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/MessageDispatcher.java @@ -318,7 +318,8 @@ void stop() { case WAIT_FOR_PROCESSING: logger.log( Level.FINE, - "WAIT_FOR_PROCESSING shutdown mode: Waiting for outstanding messages to complete processing."); + "WAIT_FOR_PROCESSING shutdown mode: Waiting for outstanding messages to complete" + + " processing."); java.time.Duration timeout = subscriberShutdownSettings.getTimeout(); if (timeout.isNegative()) { // Indefinite wait use existing blocking wait @@ -330,7 +331,8 @@ void stop() { if (!completedWait) { logger.log( Level.WARNING, - "Grace period expired for WAIT_FOR_PROCESSING shutdown. Nacking remaining messages."); + "Grace period expired for WAIT_FOR_PROCESSING shutdown. Nacking remaining" + + " messages."); // Switch to NACK_IMMEDIATELY behavior for remaining messages nackAllOutstandingMessages(); } diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java index 28ba62d8e..c0779ff29 100644 --- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java +++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java @@ -796,7 +796,8 @@ public Builder setOpenTelemetry(OpenTelemetry openTelemetry) { * SubscriberShutdownSettings#newBuilder() default settings}. */ @BetaApi( - "The surface for SubscriberShutdownSettings is not stable yet and may be changed in the future.") + "The surface for SubscriberShutdownSettings is not stable yet and may be changed in the" + + " future.") public Builder setSubscriberShutdownSettings( SubscriberShutdownSettings subscriberShutdownSettings) { this.subscriberShutdownSettings = Preconditions.checkNotNull(subscriberShutdownSettings); diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java deleted file mode 100644 index efd8e10db..000000000 --- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.cloud.pubsub.v1; - -import com.google.common.base.Preconditions; -import java.time.Duration; - -/** - * Settings for configuring the shutdown behavior of a {@link Subscriber}. - * - *

This class allows customization of how the subscriber handles outstanding messages during - * shutdown, including whether to wait for processing to complete or to immediately nack messages, - * and an optional timeout for the shutdown process. - */ -public final class SubscriberShutdownSettings { - - /** Defines the behavior for handling outstanding messages during subscriber shutdown. */ - public enum ShutdownMode { - /** - * The subscriber will wait for all outstanding messages to be processed (acked or nacked by the - * user's message receiver) before completing the shutdown. - */ - WAIT_FOR_PROCESSING, - /** - * The subscriber will immediately nack all outstanding messages and attempt to shut down as - * quickly as possible. Messages delivered to the user callback but not yet acked/nacked will - * also be nacked. - */ - NACK_IMMEDIATELY - } - - private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(-1); // Indicates no timeout - private static final ShutdownMode DEFAULT_MODE = ShutdownMode.WAIT_FOR_PROCESSING; - - private final ShutdownMode mode; - private final Duration timeout; - - private SubscriberShutdownSettings(Builder builder) { - this.mode = builder.mode; - this.timeout = builder.timeout; - } - - /** Returns the configured shutdown mode. */ - public ShutdownMode getMode() { - return mode; - } - - /** Returns the configured shutdown timeout. A negative duration indicates no timeout. */ - public Duration getTimeout() { - return timeout; - } - - /** Returns a new builder for {@code SubscriberShutdownSettings}. */ - public static Builder newBuilder() { - return new Builder(); - } - - /** Builder for {@code SubscriberShutdownSettings}. */ - public static final class Builder { - private ShutdownMode mode = DEFAULT_MODE; - private Duration timeout = DEFAULT_TIMEOUT; - - private Builder() {} - - /** Sets the shutdown mode. Defaults to {@link ShutdownMode#WAIT_FOR_PROCESSING}. */ - public Builder setMode(ShutdownMode mode) { - this.mode = Preconditions.checkNotNull(mode); - return this; - } - - /** - * Sets the shutdown timeout. Defaults to a negative duration, indicating no timeout. - * - *

A positive duration specifies the maximum time to wait for shutdown to complete. A - * duration of zero indicates an immediate, forceful shutdown. A negative duration indicates an - * indefinite wait. - */ - public Builder setTimeout(Duration timeout) { - this.timeout = Preconditions.checkNotNull(timeout); - return this; - } - - /** Builds an instance of {@code SubscriberShutdownSettings}. */ - public SubscriberShutdownSettings build() { - return new SubscriberShutdownSettings(this); - } - } -} diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java deleted file mode 100644 index f82937582..000000000 --- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.cloud.pubsub.v1; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import com.google.cloud.pubsub.v1.SubscriberShutdownSettings.ShutdownMode; -import java.time.Duration; -import org.junit.Test; - -public class SubscriberShutdownSettingsTest { - - @Test - public void testDefaultSettings() { - SubscriberShutdownSettings settings = SubscriberShutdownSettings.newBuilder().build(); - - assertNotNull(settings); - assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); - assertTrue(settings.getTimeout().isNegative()); // Indefinite timeout - } - - @Test - public void testWaitForProcessingWithCustomTimeout() { - Duration customTimeout = Duration.ofSeconds(30); - SubscriberShutdownSettings settings = - SubscriberShutdownSettings.newBuilder() - .setMode(ShutdownMode.WAIT_FOR_PROCESSING) - .setTimeout(customTimeout) - .build(); - - assertNotNull(settings); - assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); - assertEquals(customTimeout, settings.getTimeout()); - } - - @Test - public void testNackImmediatelyWithDefaultTimeout() { - SubscriberShutdownSettings settings = - SubscriberShutdownSettings.newBuilder().setMode(ShutdownMode.NACK_IMMEDIATELY).build(); - - assertNotNull(settings); - assertEquals(ShutdownMode.NACK_IMMEDIATELY, settings.getMode()); - assertTrue(settings.getTimeout().isNegative()); // Indefinite timeout - } - - @Test - public void testNackImmediatelyWithCustomTimeout() { - Duration customTimeout = Duration.ofSeconds(10); - SubscriberShutdownSettings settings = - SubscriberShutdownSettings.newBuilder() - .setMode(ShutdownMode.NACK_IMMEDIATELY) - .setTimeout(customTimeout) - .build(); - - assertNotNull(settings); - assertEquals(ShutdownMode.NACK_IMMEDIATELY, settings.getMode()); - assertEquals(customTimeout, settings.getTimeout()); - } - - @Test - public void testZeroTimeout() { - Duration zeroTimeout = Duration.ZERO; - SubscriberShutdownSettings settings = - SubscriberShutdownSettings.newBuilder() - .setMode(ShutdownMode.WAIT_FOR_PROCESSING) - .setTimeout(zeroTimeout) - .build(); - - assertNotNull(settings); - assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); - assertEquals(zeroTimeout, settings.getTimeout()); - assertTrue(settings.getTimeout().isZero()); - } - - @Test(expected = NullPointerException.class) - public void testNullModeThrowsException() { - SubscriberShutdownSettings.newBuilder().setMode(null).build(); - } - - @Test(expected = NullPointerException.class) - public void testNullTimeoutThrowsException() { - SubscriberShutdownSettings.newBuilder().setTimeout(null).build(); - } -} From 230be0c13c1a50846d73b10211f087e57db4e738 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Thu, 9 Oct 2025 03:29:42 +0000 Subject: [PATCH 6/9] chore: generate libraries at Thu Oct 9 03:27:44 UTC 2025 --- .github/workflows/update_generation_config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml index 59e39834d..a7e14bb48 100644 --- a/.github/workflows/update_generation_config.yaml +++ b/.github/workflows/update_generation_config.yaml @@ -26,7 +26,7 @@ jobs: # the branch into which the pull request is merged base_branch: main steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} From beb6d3d02934ad4f383da5e7a83cb8b1dd62712f Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Wed, 15 Oct 2025 03:34:24 +0000 Subject: [PATCH 7/9] chore: generate libraries at Wed Oct 15 03:32:28 UTC 2025 --- .github/workflows/update_generation_config.yaml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml index 59e39834d..a7e14bb48 100644 --- a/.github/workflows/update_generation_config.yaml +++ b/.github/workflows/update_generation_config.yaml @@ -26,7 +26,7 @@ jobs: # the branch into which the pull request is merged base_branch: main steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} diff --git a/README.md b/README.md index 5e43686c1..4d9a3de62 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.69.0 + 26.70.0 pom import @@ -43,7 +43,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-pubsub - 1.141.5 + 1.142.0 ``` From a59970edfbc7d1474ea329de54d9634de9dc7bcf Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 21 Oct 2025 21:54:52 -0400 Subject: [PATCH 8/9] chore: Ignore hermetic build --- .../hermetic_library_generation.yaml | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml index 7023350ad..12967958f 100644 --- a/.github/workflows/hermetic_library_generation.yaml +++ b/.github/workflows/hermetic_library_generation.yaml @@ -13,33 +13,33 @@ # limitations under the License. # GitHub action job to test core java library features on # downstream client libraries before they are released. -name: Hermetic library generation upon generation config change through pull requests -on: - pull_request: - -env: - REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }} - GITHUB_REPOSITORY: ${{ github.repository }} -jobs: - library_generation: - runs-on: ubuntu-latest - steps: - - name: Determine whether the pull request comes from a fork - run: | - if [[ "${GITHUB_REPOSITORY}" != "${REPO_FULL_NAME}" ]]; then - echo "This PR comes from a fork. Skip library generation." - echo "SHOULD_RUN=false" >> $GITHUB_ENV - else - echo "SHOULD_RUN=true" >> $GITHUB_ENV - fi - - uses: actions/checkout@v5 - if: env.SHOULD_RUN == 'true' - with: - fetch-depth: 0 - token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} - - uses: googleapis/sdk-platform-java/.github/scripts@v2.63.0 - if: env.SHOULD_RUN == 'true' - with: - base_ref: ${{ github.base_ref }} - head_ref: ${{ github.head_ref }} - token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} +#name: Hermetic library generation upon generation config change through pull requests +#on: +# pull_request: +# +#env: +# REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }} +# GITHUB_REPOSITORY: ${{ github.repository }} +#jobs: +# library_generation: +# runs-on: ubuntu-latest +# steps: +# - name: Determine whether the pull request comes from a fork +# run: | +# if [[ "${GITHUB_REPOSITORY}" != "${REPO_FULL_NAME}" ]]; then +# echo "This PR comes from a fork. Skip library generation." +# echo "SHOULD_RUN=false" >> $GITHUB_ENV +# else +# echo "SHOULD_RUN=true" >> $GITHUB_ENV +# fi +# - uses: actions/checkout@v5 +# if: env.SHOULD_RUN == 'true' +# with: +# fetch-depth: 0 +# token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} +# - uses: googleapis/sdk-platform-java/.github/scripts@v2.63.0 +# if: env.SHOULD_RUN == 'true' +# with: +# base_ref: ${{ github.base_ref }} +# head_ref: ${{ github.head_ref }} +# token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} From c0f9a4f9d84e76c717387b23a5a8dca5b2bc3d53 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Tue, 21 Oct 2025 21:57:16 -0400 Subject: [PATCH 9/9] chore: Restore deleted files --- .../pubsub/v1/SubscriberShutdownSettings.java | 102 ++++++++++++++++++ .../v1/SubscriberShutdownSettingsTest.java | 100 +++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java create mode 100644 google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java new file mode 100644 index 000000000..efd8e10db --- /dev/null +++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettings.java @@ -0,0 +1,102 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.pubsub.v1; + +import com.google.common.base.Preconditions; +import java.time.Duration; + +/** + * Settings for configuring the shutdown behavior of a {@link Subscriber}. + * + *

This class allows customization of how the subscriber handles outstanding messages during + * shutdown, including whether to wait for processing to complete or to immediately nack messages, + * and an optional timeout for the shutdown process. + */ +public final class SubscriberShutdownSettings { + + /** Defines the behavior for handling outstanding messages during subscriber shutdown. */ + public enum ShutdownMode { + /** + * The subscriber will wait for all outstanding messages to be processed (acked or nacked by the + * user's message receiver) before completing the shutdown. + */ + WAIT_FOR_PROCESSING, + /** + * The subscriber will immediately nack all outstanding messages and attempt to shut down as + * quickly as possible. Messages delivered to the user callback but not yet acked/nacked will + * also be nacked. + */ + NACK_IMMEDIATELY + } + + private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(-1); // Indicates no timeout + private static final ShutdownMode DEFAULT_MODE = ShutdownMode.WAIT_FOR_PROCESSING; + + private final ShutdownMode mode; + private final Duration timeout; + + private SubscriberShutdownSettings(Builder builder) { + this.mode = builder.mode; + this.timeout = builder.timeout; + } + + /** Returns the configured shutdown mode. */ + public ShutdownMode getMode() { + return mode; + } + + /** Returns the configured shutdown timeout. A negative duration indicates no timeout. */ + public Duration getTimeout() { + return timeout; + } + + /** Returns a new builder for {@code SubscriberShutdownSettings}. */ + public static Builder newBuilder() { + return new Builder(); + } + + /** Builder for {@code SubscriberShutdownSettings}. */ + public static final class Builder { + private ShutdownMode mode = DEFAULT_MODE; + private Duration timeout = DEFAULT_TIMEOUT; + + private Builder() {} + + /** Sets the shutdown mode. Defaults to {@link ShutdownMode#WAIT_FOR_PROCESSING}. */ + public Builder setMode(ShutdownMode mode) { + this.mode = Preconditions.checkNotNull(mode); + return this; + } + + /** + * Sets the shutdown timeout. Defaults to a negative duration, indicating no timeout. + * + *

A positive duration specifies the maximum time to wait for shutdown to complete. A + * duration of zero indicates an immediate, forceful shutdown. A negative duration indicates an + * indefinite wait. + */ + public Builder setTimeout(Duration timeout) { + this.timeout = Preconditions.checkNotNull(timeout); + return this; + } + + /** Builds an instance of {@code SubscriberShutdownSettings}. */ + public SubscriberShutdownSettings build() { + return new SubscriberShutdownSettings(this); + } + } +} diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java new file mode 100644 index 000000000..f82937582 --- /dev/null +++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SubscriberShutdownSettingsTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.pubsub.v1; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.pubsub.v1.SubscriberShutdownSettings.ShutdownMode; +import java.time.Duration; +import org.junit.Test; + +public class SubscriberShutdownSettingsTest { + + @Test + public void testDefaultSettings() { + SubscriberShutdownSettings settings = SubscriberShutdownSettings.newBuilder().build(); + + assertNotNull(settings); + assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); + assertTrue(settings.getTimeout().isNegative()); // Indefinite timeout + } + + @Test + public void testWaitForProcessingWithCustomTimeout() { + Duration customTimeout = Duration.ofSeconds(30); + SubscriberShutdownSettings settings = + SubscriberShutdownSettings.newBuilder() + .setMode(ShutdownMode.WAIT_FOR_PROCESSING) + .setTimeout(customTimeout) + .build(); + + assertNotNull(settings); + assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); + assertEquals(customTimeout, settings.getTimeout()); + } + + @Test + public void testNackImmediatelyWithDefaultTimeout() { + SubscriberShutdownSettings settings = + SubscriberShutdownSettings.newBuilder().setMode(ShutdownMode.NACK_IMMEDIATELY).build(); + + assertNotNull(settings); + assertEquals(ShutdownMode.NACK_IMMEDIATELY, settings.getMode()); + assertTrue(settings.getTimeout().isNegative()); // Indefinite timeout + } + + @Test + public void testNackImmediatelyWithCustomTimeout() { + Duration customTimeout = Duration.ofSeconds(10); + SubscriberShutdownSettings settings = + SubscriberShutdownSettings.newBuilder() + .setMode(ShutdownMode.NACK_IMMEDIATELY) + .setTimeout(customTimeout) + .build(); + + assertNotNull(settings); + assertEquals(ShutdownMode.NACK_IMMEDIATELY, settings.getMode()); + assertEquals(customTimeout, settings.getTimeout()); + } + + @Test + public void testZeroTimeout() { + Duration zeroTimeout = Duration.ZERO; + SubscriberShutdownSettings settings = + SubscriberShutdownSettings.newBuilder() + .setMode(ShutdownMode.WAIT_FOR_PROCESSING) + .setTimeout(zeroTimeout) + .build(); + + assertNotNull(settings); + assertEquals(ShutdownMode.WAIT_FOR_PROCESSING, settings.getMode()); + assertEquals(zeroTimeout, settings.getTimeout()); + assertTrue(settings.getTimeout().isZero()); + } + + @Test(expected = NullPointerException.class) + public void testNullModeThrowsException() { + SubscriberShutdownSettings.newBuilder().setMode(null).build(); + } + + @Test(expected = NullPointerException.class) + public void testNullTimeoutThrowsException() { + SubscriberShutdownSettings.newBuilder().setTimeout(null).build(); + } +}