A zero duration effectively disables auto deadline extensions.
*/
- public Builder setMaxAckExtensionPeriod(Duration maxAckExtensionPeriod) {
+ public Builder setMaxAckExtensionPeriodDuration(java.time.Duration maxAckExtensionPeriod) {
Preconditions.checkArgument(maxAckExtensionPeriod.toMillis() >= 0);
this.maxAckExtensionPeriod = maxAckExtensionPeriod;
return this;
}
+ /**
+ * This method is obsolete. Use {@link
+ * #setMaxDurationPerAckExtensionDuration(java.time.Duration)} instead.
+ */
+ @ObsoleteApi("Use setMaxDurationPerAckExtensionDuration(java.time.Duration) instead")
+ public Builder setMaxDurationPerAckExtension(
+ org.threeten.bp.Duration maxDurationPerAckExtension) {
+ return setMaxDurationPerAckExtensionDuration(toJavaTimeDuration(maxDurationPerAckExtension));
+ }
+
/**
* Set the upper bound for a single mod ack extention period.
*
@@ -596,7 +675,8 @@ public Builder setMaxAckExtensionPeriod(Duration maxAckExtensionPeriod) {
*
*
MaxDurationPerAckExtension configuration can be disabled by specifying a zero duration.
*/
- public Builder setMaxDurationPerAckExtension(Duration maxDurationPerAckExtension) {
+ public Builder setMaxDurationPerAckExtensionDuration(
+ java.time.Duration maxDurationPerAckExtension) {
// If a non-default min is set, make sure min is less than max
Preconditions.checkArgument(
maxDurationPerAckExtension.toMillis() >= 0
@@ -608,6 +688,16 @@ public Builder setMaxDurationPerAckExtension(Duration maxDurationPerAckExtension
return this;
}
+ /**
+ * This method is obsolete. Use {@link
+ * #setMinDurationPerAckExtensionDuration(java.time.Duration)} instead.
+ */
+ @ObsoleteApi("Use setMinDurationPerAckExtensionDuration(java.time.Duration) instead")
+ public Builder setMinDurationPerAckExtension(
+ org.threeten.bp.Duration minDurationPerAckExtension) {
+ return setMinDurationPerAckExtensionDuration(toJavaTimeDuration(minDurationPerAckExtension));
+ }
+
/**
* Set the lower bound for a single mod ack extention period.
*
@@ -618,7 +708,8 @@ public Builder setMaxDurationPerAckExtension(Duration maxDurationPerAckExtension
*
*
MinDurationPerAckExtension configuration can be disabled by specifying a zero duration.
*/
- public Builder setMinDurationPerAckExtension(Duration minDurationPerAckExtension) {
+ public Builder setMinDurationPerAckExtensionDuration(
+ java.time.Duration minDurationPerAckExtension) {
// If a non-default max is set, make sure min is less than max
Preconditions.checkArgument(
minDurationPerAckExtension.toMillis() >= 0
@@ -670,12 +761,51 @@ public Builder setEndpoint(String endpoint) {
return this;
}
+ /** Gives the ability to override the universe domain. */
+ public Builder setUniverseDomain(String universeDomain) {
+ this.universeDomain = universeDomain;
+ return this;
+ }
+
/** Gives the ability to set a custom clock. */
Builder setClock(ApiClock clock) {
this.clock = Optional.of(clock);
return this;
}
+ /**
+ * OpenTelemetry will be enabled if setEnableOpenTelemetry is true and and instance of
+ * OpenTelemetry has been provied. Warning: traces are subject to change. The name and
+ * attributes of a span might change without notice. Only use run traces interactively. Don't
+ * use in automation. Running non-interactive traces can cause problems if the underlying trace
+ * architecture changes without notice.
+ */
+
+ /** Gives the ability to enable Open Telemetry Tracing */
+ public Builder setEnableOpenTelemetryTracing(boolean enableOpenTelemetryTracing) {
+ this.enableOpenTelemetryTracing = enableOpenTelemetryTracing;
+ return this;
+ }
+
+ /** Sets the instance of OpenTelemetry for the Publisher class. */
+ public Builder setOpenTelemetry(OpenTelemetry openTelemetry) {
+ this.openTelemetry = openTelemetry;
+ return this;
+ }
+
+ /**
+ * Sets the shutdown settings for the subscriber. Defaults to {@link
+ * SubscriberShutdownSettings#newBuilder() default settings}.
+ */
+ @BetaApi(
+ "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);
+ return this;
+ }
+
/** Returns the default FlowControlSettings used by the client if settings are not provided. */
public static FlowControlSettings getDefaultFlowControlSettings() {
return DEFAULT_FLOW_CONTROL_SETTINGS;
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/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
index e7617298c..828bbea14 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -100,352 +100,352 @@
* close().
*
*
- * Methods
+ * Methods
*
* | Method |
* Description |
* Method Variants |
*
*
- * | CreateSubscription |
+ * CreateSubscription |
* Creates a subscription to a given topic. See the [resource name rules] (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). If the subscription already exists, returns `ALREADY_EXISTS`. If the corresponding topic doesn't exist, returns `NOT_FOUND`.
* If the name is not provided in the request, the server will assign a random name for this subscription on the same project as the topic, conforming to the [resource name format] (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). The generated name is populated in the returned Subscription object. Note that for REST API requests, you must specify a name in the request. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - createSubscription(SubscriptionName name, TopicName topic, PushConfig pushConfig, int ackDeadlineSeconds)
- *
- createSubscription(SubscriptionName name, String topic, PushConfig pushConfig, int ackDeadlineSeconds)
- *
- createSubscription(String name, TopicName topic, PushConfig pushConfig, int ackDeadlineSeconds)
- *
- createSubscription(String name, String topic, PushConfig pushConfig, int ackDeadlineSeconds)
+ *
createSubscription(SubscriptionName name, TopicName topic, PushConfig pushConfig, int ackDeadlineSeconds)
+ * createSubscription(SubscriptionName name, String topic, PushConfig pushConfig, int ackDeadlineSeconds)
+ * createSubscription(String name, TopicName topic, PushConfig pushConfig, int ackDeadlineSeconds)
+ * createSubscription(String name, String topic, PushConfig pushConfig, int ackDeadlineSeconds)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | GetSubscription |
+ * GetSubscription |
* Gets the configuration details of a subscription. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | UpdateSubscription |
- * Updates an existing subscription. Note that certain properties of a subscription, such as its topic, are not modifiable. |
+ * UpdateSubscription |
+ * Updates an existing subscription by updating the fields specified in the update mask. Note that certain properties of a subscription, such as its topic, are not modifiable. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | ListSubscriptions |
+ * ListSubscriptions |
* Lists matching subscriptions. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | DeleteSubscription |
+ * DeleteSubscription |
* Deletes an existing subscription. All messages retained in the subscription are immediately dropped. Calls to `Pull` after deletion will return `NOT_FOUND`. After a subscription is deleted, a new one may be created with the same name, but the new one has no association with the old subscription or its topic unless the same topic is specified. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | ModifyAckDeadline |
+ * ModifyAckDeadline |
* Modifies the ack deadline for a specific message. This method is useful to indicate that more time is needed to process a message by the subscriber, or to make the message available for redelivery if the processing was interrupted. Note that this does not modify the subscription-level `ackDeadlineSeconds` used for subsequent messages. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - modifyAckDeadline(SubscriptionName subscription, List<String> ackIds, int ackDeadlineSeconds)
- *
- modifyAckDeadline(String subscription, List<String> ackIds, int ackDeadlineSeconds)
+ *
modifyAckDeadline(SubscriptionName subscription, List<String> ackIds, int ackDeadlineSeconds)
+ * modifyAckDeadline(String subscription, List<String> ackIds, int ackDeadlineSeconds)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | Acknowledge |
+ * Acknowledge |
* Acknowledges the messages associated with the `ack_ids` in the `AcknowledgeRequest`. The Pub/Sub system can remove the relevant messages from the subscription.
* Acknowledging a message whose ack deadline has expired may succeed, but such a message may be redelivered later. Acknowledging a message more than once will not result in an error. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - acknowledge(SubscriptionName subscription, List<String> ackIds)
- *
- acknowledge(String subscription, List<String> ackIds)
+ *
acknowledge(SubscriptionName subscription, List<String> ackIds)
+ * acknowledge(String subscription, List<String> ackIds)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - acknowledgeCallable()
+ *
acknowledgeCallable()
*
* |
*
*
- * | Pull |
+ * Pull |
* Pulls messages from the server. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - pull(SubscriptionName subscription, int maxMessages)
- *
- pull(String subscription, int maxMessages)
- *
- pull(SubscriptionName subscription, boolean returnImmediately, int maxMessages)
- *
- pull(String subscription, boolean returnImmediately, int maxMessages)
+ *
pull(SubscriptionName subscription, int maxMessages)
+ * pull(String subscription, int maxMessages)
+ * pull(SubscriptionName subscription, boolean returnImmediately, int maxMessages)
+ * pull(String subscription, boolean returnImmediately, int maxMessages)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - pullCallable()
+ *
pullCallable()
*
* |
*
*
- * | StreamingPull |
- * Establishes a stream with the server, which sends messages down to the client. The client streams acknowledgements and ack deadline modifications back to the server. The server will close the stream and return the status on any error. The server may close the stream with status `UNAVAILABLE` to reassign server-side resources, in which case, the client should re-establish the stream. Flow control can be achieved by configuring the underlying RPC channel. |
+ * StreamingPull |
+ * Establishes a stream with the server, which sends messages down to the client. The client streams acknowledgments and ack deadline modifications back to the server. The server will close the stream and return the status on any error. The server may close the stream with status `UNAVAILABLE` to reassign server-side resources, in which case, the client should re-establish the stream. Flow control can be achieved by configuring the underlying RPC channel. |
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | ModifyPushConfig |
+ * ModifyPushConfig |
* Modifies the `PushConfig` for a specified subscription.
* This may be used to change a push subscription to a pull one (signified by an empty `PushConfig`) or vice versa, or change the endpoint URL and other attributes of a push subscription. Messages will accumulate for delivery continuously through the call regardless of changes to the `PushConfig`. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - modifyPushConfig(SubscriptionName subscription, PushConfig pushConfig)
- *
- modifyPushConfig(String subscription, PushConfig pushConfig)
+ *
modifyPushConfig(SubscriptionName subscription, PushConfig pushConfig)
+ * modifyPushConfig(String subscription, PushConfig pushConfig)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | GetSnapshot |
+ * GetSnapshot |
* Gets the configuration details of a snapshot. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - getSnapshotCallable()
+ *
getSnapshotCallable()
*
* |
*
*
- * | ListSnapshots |
+ * ListSnapshots |
* Lists the existing snapshots. Snapshots are used in [Seek]( https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | CreateSnapshot |
+ * CreateSnapshot |
* Creates a snapshot from the requested subscription. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. If the snapshot already exists, returns `ALREADY_EXISTS`. If the requested subscription doesn't exist, returns `NOT_FOUND`. If the backlog in the subscription is too old -- and the resulting snapshot would expire in less than 1 hour -- then `FAILED_PRECONDITION` is returned. See also the `Snapshot.expire_time` field. If the name is not provided in the request, the server will assign a random name for this snapshot on the same project as the subscription, conforming to the [resource name format] (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). The generated name is populated in the returned Snapshot object. Note that for REST API requests, you must specify a name in the request. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - createSnapshot(SnapshotName name, SubscriptionName subscription)
- *
- createSnapshot(SnapshotName name, String subscription)
- *
- createSnapshot(String name, SubscriptionName subscription)
- *
- createSnapshot(String name, String subscription)
+ *
createSnapshot(SnapshotName name, SubscriptionName subscription)
+ * createSnapshot(SnapshotName name, String subscription)
+ * createSnapshot(String name, SubscriptionName subscription)
+ * createSnapshot(String name, String subscription)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | UpdateSnapshot |
- * Updates an existing snapshot. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. |
+ * UpdateSnapshot |
+ * Updates an existing snapshot by updating the fields specified in the update mask. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | DeleteSnapshot |
+ * DeleteSnapshot |
* Removes an existing snapshot. Snapshots are used in [Seek] (https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. When the snapshot is deleted, all messages retained in the snapshot are immediately dropped. After a snapshot is deleted, a new one may be created with the same name, but the new one has no association with the old snapshot or its subscription, unless the same subscription is specified. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | Seek |
+ * Seek |
* Seeks an existing subscription to a point in time or to a given snapshot, whichever is provided in the request. Snapshots are used in [Seek] (https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. Note that both the subscription and the snapshot must be on the same topic. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - seekCallable()
+ *
seekCallable()
*
* |
*
*
- * | SetIamPolicy |
+ * SetIamPolicy |
* Sets the access control policy on the specified resource. Replacesany existing policy.
* Can return `NOT_FOUND`, `INVALID_ARGUMENT`, and `PERMISSION_DENIED`errors. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - setIamPolicyCallable()
+ *
setIamPolicyCallable()
*
* |
*
*
- * | GetIamPolicy |
+ * GetIamPolicy |
* Gets the access control policy for a resource. Returns an empty policyif the resource exists and does not have a policy set. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - getIamPolicyCallable()
+ *
getIamPolicyCallable()
*
* |
*
*
- * | TestIamPermissions |
+ * TestIamPermissions |
* Returns permissions that a caller has on the specified resource. If theresource does not exist, this will return an empty set ofpermissions, not a `NOT_FOUND` error.
* Note: This operation is designed to be used for buildingpermission-aware UIs and command-line tools, not for authorizationchecking. This operation may "fail open" without warning. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
@@ -588,7 +588,7 @@ public SubscriberStub getStub() {
* }
* }
*
- * @param name Required. The name of the subscription. It must have the format
+ * @param name Required. Identifier. The name of the subscription. It must have the format
* `"projects/{project}/subscriptions/{subscription}"`. `{subscription}` must start with a
* letter, and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores
* (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3
@@ -596,12 +596,12 @@ public SubscriberStub getStub() {
* @param topic Required. The name of the topic from which this subscription is receiving
* messages. Format is `projects/{project}/topics/{topic}`. The value of this field will be
* `_deleted-topic_` if the topic has been deleted.
- * @param pushConfig If push delivery is used with this subscription, this field is used to
- * configure it.
- * @param ackDeadlineSeconds The approximate amount of time (on a best-effort basis) Pub/Sub waits
- * for the subscriber to acknowledge receipt before resending the message. In the interval
- * after the message is delivered and before it is acknowledged, it is considered to be
- * _outstanding_. During that time period, the message will not be redelivered (on a
+ * @param pushConfig Optional. If push delivery is used with this subscription, this field is used
+ * to configure it.
+ * @param ackDeadlineSeconds Optional. The approximate amount of time (on a best-effort basis)
+ * Pub/Sub waits for the subscriber to acknowledge receipt before resending the message. In
+ * the interval after the message is delivered and before it is acknowledged, it is considered
+ * to be _outstanding_. During that time period, the message will not be redelivered (on a
* best-effort basis).
* For pull subscriptions, this value is used as the initial value for the ack deadline. To
* override this value for a given message, call `ModifyAckDeadline` with the corresponding
@@ -658,7 +658,7 @@ public final Subscription createSubscription(
* }
* }
*
- * @param name Required. The name of the subscription. It must have the format
+ * @param name Required. Identifier. The name of the subscription. It must have the format
* `"projects/{project}/subscriptions/{subscription}"`. `{subscription}` must start with a
* letter, and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores
* (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3
@@ -666,12 +666,12 @@ public final Subscription createSubscription(
* @param topic Required. The name of the topic from which this subscription is receiving
* messages. Format is `projects/{project}/topics/{topic}`. The value of this field will be
* `_deleted-topic_` if the topic has been deleted.
- * @param pushConfig If push delivery is used with this subscription, this field is used to
- * configure it.
- * @param ackDeadlineSeconds The approximate amount of time (on a best-effort basis) Pub/Sub waits
- * for the subscriber to acknowledge receipt before resending the message. In the interval
- * after the message is delivered and before it is acknowledged, it is considered to be
- * _outstanding_. During that time period, the message will not be redelivered (on a
+ * @param pushConfig Optional. If push delivery is used with this subscription, this field is used
+ * to configure it.
+ * @param ackDeadlineSeconds Optional. The approximate amount of time (on a best-effort basis)
+ * Pub/Sub waits for the subscriber to acknowledge receipt before resending the message. In
+ * the interval after the message is delivered and before it is acknowledged, it is considered
+ * to be _outstanding_. During that time period, the message will not be redelivered (on a
* best-effort basis).
*
For pull subscriptions, this value is used as the initial value for the ack deadline. To
* override this value for a given message, call `ModifyAckDeadline` with the corresponding
@@ -728,7 +728,7 @@ public final Subscription createSubscription(
* }
* }
*
- * @param name Required. The name of the subscription. It must have the format
+ * @param name Required. Identifier. The name of the subscription. It must have the format
* `"projects/{project}/subscriptions/{subscription}"`. `{subscription}` must start with a
* letter, and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores
* (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3
@@ -736,12 +736,12 @@ public final Subscription createSubscription(
* @param topic Required. The name of the topic from which this subscription is receiving
* messages. Format is `projects/{project}/topics/{topic}`. The value of this field will be
* `_deleted-topic_` if the topic has been deleted.
- * @param pushConfig If push delivery is used with this subscription, this field is used to
- * configure it.
- * @param ackDeadlineSeconds The approximate amount of time (on a best-effort basis) Pub/Sub waits
- * for the subscriber to acknowledge receipt before resending the message. In the interval
- * after the message is delivered and before it is acknowledged, it is considered to be
- * _outstanding_. During that time period, the message will not be redelivered (on a
+ * @param pushConfig Optional. If push delivery is used with this subscription, this field is used
+ * to configure it.
+ * @param ackDeadlineSeconds Optional. The approximate amount of time (on a best-effort basis)
+ * Pub/Sub waits for the subscriber to acknowledge receipt before resending the message. In
+ * the interval after the message is delivered and before it is acknowledged, it is considered
+ * to be _outstanding_. During that time period, the message will not be redelivered (on a
* best-effort basis).
*
For pull subscriptions, this value is used as the initial value for the ack deadline. To
* override this value for a given message, call `ModifyAckDeadline` with the corresponding
@@ -798,7 +798,7 @@ public final Subscription createSubscription(
* }
* }
*
- * @param name Required. The name of the subscription. It must have the format
+ * @param name Required. Identifier. The name of the subscription. It must have the format
* `"projects/{project}/subscriptions/{subscription}"`. `{subscription}` must start with a
* letter, and contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores
* (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3
@@ -806,12 +806,12 @@ public final Subscription createSubscription(
* @param topic Required. The name of the topic from which this subscription is receiving
* messages. Format is `projects/{project}/topics/{topic}`. The value of this field will be
* `_deleted-topic_` if the topic has been deleted.
- * @param pushConfig If push delivery is used with this subscription, this field is used to
- * configure it.
- * @param ackDeadlineSeconds The approximate amount of time (on a best-effort basis) Pub/Sub waits
- * for the subscriber to acknowledge receipt before resending the message. In the interval
- * after the message is delivered and before it is acknowledged, it is considered to be
- * _outstanding_. During that time period, the message will not be redelivered (on a
+ * @param pushConfig Optional. If push delivery is used with this subscription, this field is used
+ * to configure it.
+ * @param ackDeadlineSeconds Optional. The approximate amount of time (on a best-effort basis)
+ * Pub/Sub waits for the subscriber to acknowledge receipt before resending the message. In
+ * the interval after the message is delivered and before it is acknowledged, it is considered
+ * to be _outstanding_. During that time period, the message will not be redelivered (on a
* best-effort basis).
*
For pull subscriptions, this value is used as the initial value for the ack deadline. To
* override this value for a given message, call `ModifyAckDeadline` with the corresponding
@@ -878,6 +878,10 @@ public final Subscription createSubscription(
* .setDetached(true)
* .setEnableExactlyOnceDelivery(true)
* .setTopicMessageRetentionDuration(Duration.newBuilder().build())
+ * .setAnalyticsHubSubscriptionInfo(
+ * Subscription.AnalyticsHubSubscriptionInfo.newBuilder().build())
+ * .addAllMessageTransforms(new ArrayList())
+ * .putAllTags(new HashMap())
* .build();
* Subscription response = subscriptionAdminClient.createSubscription(request);
* }
@@ -1141,6 +1145,10 @@ public final Subscription createSubscription(
* .setDetached(true)
* .setEnableExactlyOnceDelivery(true)
* .setTopicMessageRetentionDuration(Duration.newBuilder().build())
+ * .setAnalyticsHubSubscriptionInfo(
+ * Subscription.AnalyticsHubSubscriptionInfo.newBuilder().build())
+ * .addAllMessageTransforms(new ArrayList())
+ * .putAllTags(new HashMap())
* .build();
* ApiFuture future =
* subscriptionAdminClient.createSubscriptionCallable().futureCall(request);
@@ -1171,7 +1179,7 @@ public final UnaryCallable createSubscriptionCallabl
* }
* }
*
- * @param subscription Required. The name of the subscription to get. Format is
+ * @param subscription Required. Identifier. The name of the subscription to get. Format is
* `projects/{project}/subscriptions/{sub}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1201,7 +1209,7 @@ public final Subscription getSubscription(SubscriptionName subscription) {
* }
* }
*
- * @param subscription Required. The name of the subscription to get. Format is
+ * @param subscription Required. Identifier. The name of the subscription to get. Format is
* `projects/{project}/subscriptions/{sub}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1296,8 +1304,8 @@ public final UnaryCallable getSubscription
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing subscription. Note that certain properties of a subscription, such as its
- * topic, are not modifiable.
+ * Updates an existing subscription by updating the fields specified in the update mask. Note that
+ * certain properties of a subscription, such as its topic, are not modifiable.
*
* Sample code:
*
@@ -1330,8 +1338,8 @@ public final Subscription updateSubscription(Subscription subscription, FieldMas
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing subscription. Note that certain properties of a subscription, such as its
- * topic, are not modifiable.
+ * Updates an existing subscription by updating the fields specified in the update mask. Note that
+ * certain properties of a subscription, such as its topic, are not modifiable.
*
*
Sample code:
*
@@ -1360,8 +1368,8 @@ public final Subscription updateSubscription(UpdateSubscriptionRequest request)
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing subscription. Note that certain properties of a subscription, such as its
- * topic, are not modifiable.
+ * Updates an existing subscription by updating the fields specified in the update mask. Note that
+ * certain properties of a subscription, such as its topic, are not modifiable.
*
*
Sample code:
*
@@ -1408,8 +1416,8 @@ public final UnaryCallable updateSubscr
* }
* }
*
- * @param project Required. The name of the project in which to list subscriptions. Format is
- * `projects/{project-id}`.
+ * @param project Required. Identifier. The name of the project in which to list subscriptions.
+ * Format is `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final ListSubscriptionsPagedResponse listSubscriptions(ProjectName project) {
@@ -1440,8 +1448,8 @@ public final ListSubscriptionsPagedResponse listSubscriptions(ProjectName projec
* }
* }
*
- * @param project Required. The name of the project in which to list subscriptions. Format is
- * `projects/{project-id}`.
+ * @param project Required. Identifier. The name of the project in which to list subscriptions.
+ * Format is `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final ListSubscriptionsPagedResponse listSubscriptions(String project) {
@@ -1576,7 +1584,7 @@ public final ListSubscriptionsPagedResponse listSubscriptions(ListSubscriptionsR
* }
* }
*
- * @param subscription Required. The subscription to delete. Format is
+ * @param subscription Required. Identifier. The subscription to delete. Format is
* `projects/{project}/subscriptions/{sub}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1609,7 +1617,7 @@ public final void deleteSubscription(SubscriptionName subscription) {
* }
* }
*
- * @param subscription Required. The subscription to delete. Format is
+ * @param subscription Required. Identifier. The subscription to delete. Format is
* `projects/{project}/subscriptions/{sub}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1742,8 +1750,8 @@ public final UnaryCallable deleteSubscriptionC
* expire 10 seconds after the `ModifyAckDeadline` call was made. Specifying zero might
* immediately make the message available for delivery to another subscriber client. This
* typically results in an increase in the rate of message redeliveries (that is, duplicates).
- * The minimum deadline you can specify is 0 seconds. The maximum deadline you can specify is
- * 600 seconds (10 minutes).
+ * The minimum deadline you can specify is 0 seconds. The maximum deadline you can specify in
+ * a single request is 600 seconds (10 minutes).
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final void modifyAckDeadline(
@@ -1788,8 +1796,8 @@ public final void modifyAckDeadline(
* expire 10 seconds after the `ModifyAckDeadline` call was made. Specifying zero might
* immediately make the message available for delivery to another subscriber client. This
* typically results in an increase in the rate of message redeliveries (that is, duplicates).
- * The minimum deadline you can specify is 0 seconds. The maximum deadline you can specify is
- * 600 seconds (10 minutes).
+ * The minimum deadline you can specify is 0 seconds. The maximum deadline you can specify in
+ * a single request is 600 seconds (10 minutes).
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final void modifyAckDeadline(
@@ -2373,7 +2381,7 @@ public final UnaryCallable pullCallable() {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
* Establishes a stream with the server, which sends messages down to the client. The client
- * streams acknowledgements and ack deadline modifications back to the server. The server will
+ * streams acknowledgments and ack deadline modifications back to the server. The server will
* close the stream and return the status on any error. The server may close the stream with
* status `UNAVAILABLE` to reassign server-side resources, in which case, the client should
* re-establish the stream. Flow control can be achieved by configuring the underlying RPC
@@ -2400,6 +2408,7 @@ public final UnaryCallable pullCallable() {
* .setClientId("clientId908408390")
* .setMaxOutstandingMessages(-1315266996)
* .setMaxOutstandingBytes(-2103098517)
+ * .setProtocolVersion(-1161610703)
* .build();
* bidiStream.send(request);
* for (StreamingPullResponse response : bidiStream) {
@@ -2622,7 +2631,7 @@ public final UnaryCallable modifyPushConfigCalla
* }
* }
*
- * @param snapshot Required. The name of the snapshot to get. Format is
+ * @param snapshot Required. Identifier. The name of the snapshot to get. Format is
* `projects/{project}/snapshots/{snap}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -2655,7 +2664,7 @@ public final Snapshot getSnapshot(SnapshotName snapshot) {
* }
* }
*
- * @param snapshot Required. The name of the snapshot to get. Format is
+ * @param snapshot Required. Identifier. The name of the snapshot to get. Format is
* `projects/{project}/snapshots/{snap}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -2779,8 +2788,8 @@ public final UnaryCallable getSnapshotCallable() {
* }
* }
*
- * @param project Required. The name of the project in which to list snapshots. Format is
- * `projects/{project-id}`.
+ * @param project Required. Identifier. The name of the project in which to list snapshots. Format
+ * is `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final ListSnapshotsPagedResponse listSnapshots(ProjectName project) {
@@ -2814,8 +2823,8 @@ public final ListSnapshotsPagedResponse listSnapshots(ProjectName project) {
* }
* }
*
- * @param project Required. The name of the project in which to list snapshots. Format is
- * `projects/{project-id}`.
+ * @param project Required. Identifier. The name of the project in which to list snapshots. Format
+ * is `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
public final ListSnapshotsPagedResponse listSnapshots(String project) {
@@ -2966,10 +2975,11 @@ public final UnaryCallable listSnap
* }
* }
*
- * @param name Required. User-provided name for this snapshot. If the name is not provided in the
- * request, the server will assign a random name for this snapshot on the same project as the
- * subscription. Note that for REST API requests, you must specify a name. See the [resource
- * name rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
+ * @param name Required. Identifier. User-provided name for this snapshot. If the name is not
+ * provided in the request, the server will assign a random name for this snapshot on the same
+ * project as the subscription. Note that for REST API requests, you must specify a name. See
+ * the [resource name
+ * rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
* `projects/{project}/snapshots/{snap}`.
* @param subscription Required. The subscription whose backlog the snapshot retains.
* Specifically, the created snapshot is guaranteed to retain: (a) The existing backlog on the
@@ -3019,10 +3029,11 @@ public final Snapshot createSnapshot(SnapshotName name, SubscriptionName subscri
* }
* }
*
- * @param name Required. User-provided name for this snapshot. If the name is not provided in the
- * request, the server will assign a random name for this snapshot on the same project as the
- * subscription. Note that for REST API requests, you must specify a name. See the [resource
- * name rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
+ * @param name Required. Identifier. User-provided name for this snapshot. If the name is not
+ * provided in the request, the server will assign a random name for this snapshot on the same
+ * project as the subscription. Note that for REST API requests, you must specify a name. See
+ * the [resource name
+ * rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
* `projects/{project}/snapshots/{snap}`.
* @param subscription Required. The subscription whose backlog the snapshot retains.
* Specifically, the created snapshot is guaranteed to retain: (a) The existing backlog on the
@@ -3072,10 +3083,11 @@ public final Snapshot createSnapshot(SnapshotName name, String subscription) {
* }
* }
*
- * @param name Required. User-provided name for this snapshot. If the name is not provided in the
- * request, the server will assign a random name for this snapshot on the same project as the
- * subscription. Note that for REST API requests, you must specify a name. See the [resource
- * name rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
+ * @param name Required. Identifier. User-provided name for this snapshot. If the name is not
+ * provided in the request, the server will assign a random name for this snapshot on the same
+ * project as the subscription. Note that for REST API requests, you must specify a name. See
+ * the [resource name
+ * rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
* `projects/{project}/snapshots/{snap}`.
* @param subscription Required. The subscription whose backlog the snapshot retains.
* Specifically, the created snapshot is guaranteed to retain: (a) The existing backlog on the
@@ -3125,10 +3137,11 @@ public final Snapshot createSnapshot(String name, SubscriptionName subscription)
* }
* }
*
- * @param name Required. User-provided name for this snapshot. If the name is not provided in the
- * request, the server will assign a random name for this snapshot on the same project as the
- * subscription. Note that for REST API requests, you must specify a name. See the [resource
- * name rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
+ * @param name Required. Identifier. User-provided name for this snapshot. If the name is not
+ * provided in the request, the server will assign a random name for this snapshot on the same
+ * project as the subscription. Note that for REST API requests, you must specify a name. See
+ * the [resource name
+ * rules](https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). Format is
* `projects/{project}/snapshots/{snap}`.
* @param subscription Required. The subscription whose backlog the snapshot retains.
* Specifically, the created snapshot is guaranteed to retain: (a) The existing backlog on the
@@ -3174,6 +3187,7 @@ public final Snapshot createSnapshot(String name, String subscription) {
* .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString())
* .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString())
* .putAllLabels(new HashMap())
+ * .putAllTags(new HashMap())
* .build();
* Snapshot response = subscriptionAdminClient.createSnapshot(request);
* }
@@ -3366,6 +3380,7 @@ public final Snapshot createSnapshot(ProjectSnapshotName name, String subscripti
* .setName(SnapshotName.of("[PROJECT]", "[SNAPSHOT]").toString())
* .setSubscription(SubscriptionName.of("[PROJECT]", "[SUBSCRIPTION]").toString())
* .putAllLabels(new HashMap())
+ * .putAllTags(new HashMap())
* .build();
* ApiFuture future =
* subscriptionAdminClient.createSnapshotCallable().futureCall(request);
@@ -3380,9 +3395,9 @@ public final UnaryCallable createSnapshotCallab
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing snapshot. Snapshots are used in
- * [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to
- * manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
+ * Updates an existing snapshot by updating the fields specified in the update mask. Snapshots are
+ * used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow
+ * you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
* messages in an existing subscription to the state captured by a snapshot.
*
* Sample code:
@@ -3413,9 +3428,9 @@ public final Snapshot updateSnapshot(Snapshot snapshot, FieldMask updateMask) {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing snapshot. Snapshots are used in
- * [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to
- * manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
+ * Updates an existing snapshot by updating the fields specified in the update mask. Snapshots are
+ * used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow
+ * you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
* messages in an existing subscription to the state captured by a snapshot.
*
*
Sample code:
@@ -3445,9 +3460,9 @@ public final Snapshot updateSnapshot(UpdateSnapshotRequest request) {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing snapshot. Snapshots are used in
- * [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to
- * manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
+ * Updates an existing snapshot by updating the fields specified in the update mask. Snapshots are
+ * used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow
+ * you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of
* messages in an existing subscription to the state captured by a snapshot.
*
*
Sample code:
@@ -3499,7 +3514,7 @@ public final UnaryCallable updateSnapshotCallab
* }
* }
*
- * @param snapshot Required. The name of the snapshot to delete. Format is
+ * @param snapshot Required. Identifier. The name of the snapshot to delete. Format is
* `projects/{project}/snapshots/{snap}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -3535,7 +3550,7 @@ public final void deleteSnapshot(SnapshotName snapshot) {
* }
* }
*
- * @param snapshot Required. The name of the snapshot to delete. Format is
+ * @param snapshot Required. Identifier. The name of the snapshot to delete. Format is
* `projects/{project}/snapshots/{snap}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminSettings.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminSettings.java
index 7f50be718..ccbf48885 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminSettings.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/SubscriptionAdminSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -80,7 +80,9 @@
* The builder of this class is recursive, so contained classes are themselves builders. When
* build() is called, the tree of builders is called to create the complete settings object.
*
- *
For example, to set the total timeout of createSubscription to 30 seconds:
+ *
For example, to set the
+ * [RetrySettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.retrying.RetrySettings)
+ * of createSubscription:
*
*
{@code
* // This snippet has been automatically generated and should be regarded as a code template only.
@@ -97,10 +99,21 @@
* .createSubscriptionSettings()
* .getRetrySettings()
* .toBuilder()
- * .setTotalTimeout(Duration.ofSeconds(30))
+ * .setInitialRetryDelayDuration(Duration.ofSeconds(1))
+ * .setInitialRpcTimeoutDuration(Duration.ofSeconds(5))
+ * .setMaxAttempts(5)
+ * .setMaxRetryDelayDuration(Duration.ofSeconds(30))
+ * .setMaxRpcTimeoutDuration(Duration.ofSeconds(60))
+ * .setRetryDelayMultiplier(1.3)
+ * .setRpcTimeoutMultiplier(1.5)
+ * .setTotalTimeoutDuration(Duration.ofSeconds(300))
* .build());
* SubscriptionAdminSettings subscriptionAdminSettings = subscriptionAdminSettingsBuilder.build();
* }
+ *
+ * Please refer to the [Client Side Retry
+ * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
+ * additional support in setting retries.
*/
@Generated("by gapic-generator-java")
public class SubscriptionAdminSettings extends ClientSettings {
@@ -246,7 +259,6 @@ public static TransportChannelProvider defaultTransportChannelProvider() {
return SubscriberStubSettings.defaultTransportChannelProvider();
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() {
return SubscriberStubSettings.defaultApiClientHeaderProviderBuilder();
}
@@ -257,7 +269,6 @@ public static Builder newBuilder() {
}
/** Returns a new REST builder for this class. */
- @BetaApi
public static Builder newHttpJsonBuilder() {
return Builder.createHttpJsonDefault();
}
@@ -299,7 +310,6 @@ private static Builder createDefault() {
return new Builder(SubscriberStubSettings.newBuilder());
}
- @BetaApi
private static Builder createHttpJsonDefault() {
return new Builder(SubscriberStubSettings.newHttpJsonBuilder());
}
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminClient.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminClient.java
index 4e2652585..d5433f8ee 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminClient.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -81,221 +81,221 @@
* threads. In the example above, try-with-resources is used, which automatically calls close().
*
*
- * Methods
+ * Methods
*
* | Method |
* Description |
* Method Variants |
*
*
- * | CreateTopic |
+ * CreateTopic |
* Creates the given topic with the given name. See the [resource name rules] (https://cloud.google.com/pubsub/docs/pubsub-basics#resource_names). |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - createTopicCallable()
+ *
createTopicCallable()
*
* |
*
*
- * | UpdateTopic |
- * Updates an existing topic. Note that certain properties of a topic are not modifiable. |
+ * UpdateTopic |
+ * Updates an existing topic by updating the fields specified in the update mask. Note that certain properties of a topic are not modifiable. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - updateTopicCallable()
+ *
updateTopicCallable()
*
* |
*
*
- * | Publish |
+ * Publish |
* Adds one or more messages to the topic. Returns `NOT_FOUND` if the topic does not exist. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
- * - publish(TopicName topic, List<PubsubMessage> messages)
- *
- publish(String topic, List<PubsubMessage> messages)
+ *
publish(TopicName topic, List<PubsubMessage> messages)
+ * publish(String topic, List<PubsubMessage> messages)
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - publishCallable()
+ *
publishCallable()
*
* |
*
*
- * | GetTopic |
+ * GetTopic |
* Gets the configuration of a topic. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - getTopicCallable()
+ *
getTopicCallable()
*
* |
*
*
- * | ListTopics |
+ * ListTopics |
* Lists matching topics. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | ListTopicSubscriptions |
+ * ListTopicSubscriptions |
* Lists the names of the attached subscriptions on this topic. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | ListTopicSnapshots |
+ * ListTopicSnapshots |
* Lists the names of the snapshots on this topic. Snapshots are used in [Seek](https://cloud.google.com/pubsub/docs/replay-overview) operations, which allow you to manage message acknowledgments in bulk. That is, you can set the acknowledgment state of messages in an existing subscription to the state captured by a snapshot. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | DeleteTopic |
+ * DeleteTopic |
* Deletes the topic with the given name. Returns `NOT_FOUND` if the topic does not exist. After a topic is deleted, a new topic may be created with the same name; this is an entirely new topic with none of the old configuration or subscriptions. Existing subscriptions to this topic are not deleted, but their `topic` field is set to `_deleted-topic_`. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* "Flattened" method variants have converted the fields of the request object into function parameters to enable multiple ways to call the same method.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - deleteTopicCallable()
+ *
deleteTopicCallable()
*
* |
*
*
- * | DetachSubscription |
+ * DetachSubscription |
* Detaches a subscription from this topic. All messages retained in the subscription are dropped. Subsequent `Pull` and `StreamingPull` requests will return FAILED_PRECONDITION. If the subscription is a push subscription, pushes to the endpoint will stop. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
*
- * | SetIamPolicy |
+ * SetIamPolicy |
* Sets the access control policy on the specified resource. Replacesany existing policy.
* Can return `NOT_FOUND`, `INVALID_ARGUMENT`, and `PERMISSION_DENIED`errors. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - setIamPolicyCallable()
+ *
setIamPolicyCallable()
*
* |
*
*
- * | GetIamPolicy |
+ * GetIamPolicy |
* Gets the access control policy for a resource. Returns an empty policyif the resource exists and does not have a policy set. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
- * - getIamPolicyCallable()
+ *
getIamPolicyCallable()
*
* |
*
*
- * | TestIamPermissions |
+ * TestIamPermissions |
* Returns permissions that a caller has on the specified resource. If theresource does not exist, this will return an empty set ofpermissions, not a `NOT_FOUND` error.
* Note: This operation is designed to be used for buildingpermission-aware UIs and command-line tools, not for authorizationchecking. This operation may "fail open" without warning. |
*
* Request object method variants only take one parameter, a request object, which must be constructed before the call.
*
* Callable method variants take no parameters and return an immutable API callable object, which can be used to initiate calls to the service.
*
* |
*
@@ -420,7 +420,7 @@ public PublisherStub getStub() {
* }
* }
*
- * @param name Required. The name of the topic. It must have the format
+ * @param name Required. Identifier. The name of the topic. It must have the format
* `"projects/{project}/topics/{topic}"`. `{topic}` must start with a letter, and contain only
* letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores (`_`), periods (`.`),
* tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3 and 255 characters in
@@ -451,7 +451,7 @@ public final Topic createTopic(TopicName name) {
* }
* }
*
- * @param name Required. The name of the topic. It must have the format
+ * @param name Required. Identifier. The name of the topic. It must have the format
* `"projects/{project}/topics/{topic}"`. `{topic}` must start with a letter, and contain only
* letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`), underscores (`_`), periods (`.`),
* tildes (`~`), plus (`+`) or percent signs (`%`). It must be between 3 and 255 characters in
@@ -511,10 +511,15 @@ public final Topic createTopic(ProjectTopicName name) {
* .setName(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString())
* .putAllLabels(new HashMap())
* .setMessageStoragePolicy(MessageStoragePolicy.newBuilder().build())
- * .setKmsKeyName("kmsKeyName412586233")
+ * .setKmsKeyName(
+ * CryptoKeyName.of("[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]")
+ * .toString())
* .setSchemaSettings(SchemaSettings.newBuilder().build())
* .setSatisfiesPzs(true)
* .setMessageRetentionDuration(Duration.newBuilder().build())
+ * .setIngestionDataSourceSettings(IngestionDataSourceSettings.newBuilder().build())
+ * .addAllMessageTransforms(new ArrayList())
+ * .putAllTags(new HashMap())
* .build();
* Topic response = topicAdminClient.createTopic(request);
* }
@@ -546,10 +551,15 @@ public final Topic createTopic(Topic request) {
* .setName(TopicName.ofProjectTopicName("[PROJECT]", "[TOPIC]").toString())
* .putAllLabels(new HashMap())
* .setMessageStoragePolicy(MessageStoragePolicy.newBuilder().build())
- * .setKmsKeyName("kmsKeyName412586233")
+ * .setKmsKeyName(
+ * CryptoKeyName.of("[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]")
+ * .toString())
* .setSchemaSettings(SchemaSettings.newBuilder().build())
* .setSatisfiesPzs(true)
* .setMessageRetentionDuration(Duration.newBuilder().build())
+ * .setIngestionDataSourceSettings(IngestionDataSourceSettings.newBuilder().build())
+ * .addAllMessageTransforms(new ArrayList())
+ * .putAllTags(new HashMap())
* .build();
* ApiFuture future = topicAdminClient.createTopicCallable().futureCall(request);
* // Do something.
@@ -563,7 +573,8 @@ public final UnaryCallable createTopicCallable() {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing topic. Note that certain properties of a topic are not modifiable.
+ * Updates an existing topic by updating the fields specified in the update mask. Note that
+ * certain properties of a topic are not modifiable.
*
* Sample code:
*
@@ -595,7 +606,8 @@ public final Topic updateTopic(Topic topic, FieldMask updateMask) {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing topic. Note that certain properties of a topic are not modifiable.
+ * Updates an existing topic by updating the fields specified in the update mask. Note that
+ * certain properties of a topic are not modifiable.
*
*
Sample code:
*
@@ -624,7 +636,8 @@ public final Topic updateTopic(UpdateTopicRequest request) {
// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
- * Updates an existing topic. Note that certain properties of a topic are not modifiable.
+ * Updates an existing topic by updating the fields specified in the update mask. Note that
+ * certain properties of a topic are not modifiable.
*
*
Sample code:
*
@@ -669,8 +682,8 @@ public final UnaryCallable updateTopicCallable() {
* }
* }
*
- * @param topic Required. The messages in the request will be published on this topic. Format is
- * `projects/{project}/topics/{topic}`.
+ * @param topic Required. Identifier. The messages in the request will be published on this topic.
+ * Format is `projects/{project}/topics/{topic}`.
* @param messages Required. The messages to publish.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -702,8 +715,8 @@ public final PublishResponse publish(TopicName topic, List messag
* }
* }
*
- * @param topic Required. The messages in the request will be published on this topic. Format is
- * `projects/{project}/topics/{topic}`.
+ * @param topic Required. Identifier. The messages in the request will be published on this topic.
+ * Format is `projects/{project}/topics/{topic}`.
* @param messages Required. The messages to publish.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -788,7 +801,7 @@ public final UnaryCallable publishCallable() {
* }
* }
*
- * @param topic Required. The name of the topic to get. Format is
+ * @param topic Required. Identifier. The name of the topic to get. Format is
* `projects/{project}/topics/{topic}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -816,7 +829,7 @@ public final Topic getTopic(TopicName topic) {
* }
* }
*
- * @param topic Required. The name of the topic to get. Format is
+ * @param topic Required. Identifier. The name of the topic to get. Format is
* `projects/{project}/topics/{topic}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -925,7 +938,7 @@ public final UnaryCallable getTopicCallable() {
* }
* }
*
- * @param project Required. The name of the project in which to list topics. Format is
+ * @param project Required. Identifier. The name of the project in which to list topics. Format is
* `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -957,7 +970,7 @@ public final ListTopicsPagedResponse listTopics(ProjectName project) {
* }
* }
*
- * @param project Required. The name of the project in which to list topics. Format is
+ * @param project Required. Identifier. The name of the project in which to list topics. Format is
* `projects/{project-id}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1468,7 +1481,7 @@ public final ListTopicSnapshotsPagedResponse listTopicSnapshots(
* }
* }
*
- * @param topic Required. Name of the topic to delete. Format is
+ * @param topic Required. Identifier. Name of the topic to delete. Format is
* `projects/{project}/topics/{topic}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
@@ -1499,7 +1512,7 @@ public final void deleteTopic(TopicName topic) {
* }
* }
*
- * @param topic Required. Name of the topic to delete. Format is
+ * @param topic Required. Identifier. Name of the topic to delete. Format is
* `projects/{project}/topics/{topic}`.
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
*/
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminSettings.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminSettings.java
index 9dd62bda3..927b61b2c 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminSettings.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/TopicAdminSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -73,7 +73,9 @@
* The builder of this class is recursive, so contained classes are themselves builders. When
* build() is called, the tree of builders is called to create the complete settings object.
*
- *
For example, to set the total timeout of createTopic to 30 seconds:
+ *
For example, to set the
+ * [RetrySettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.retrying.RetrySettings)
+ * of createTopic:
*
*
{@code
* // This snippet has been automatically generated and should be regarded as a code template only.
@@ -89,10 +91,21 @@
* .createTopicSettings()
* .getRetrySettings()
* .toBuilder()
- * .setTotalTimeout(Duration.ofSeconds(30))
+ * .setInitialRetryDelayDuration(Duration.ofSeconds(1))
+ * .setInitialRpcTimeoutDuration(Duration.ofSeconds(5))
+ * .setMaxAttempts(5)
+ * .setMaxRetryDelayDuration(Duration.ofSeconds(30))
+ * .setMaxRpcTimeoutDuration(Duration.ofSeconds(60))
+ * .setRetryDelayMultiplier(1.3)
+ * .setRpcTimeoutMultiplier(1.5)
+ * .setTotalTimeoutDuration(Duration.ofSeconds(300))
* .build());
* TopicAdminSettings topicAdminSettings = topicAdminSettingsBuilder.build();
* }
+ *
+ * Please refer to the [Client Side Retry
+ * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
+ * additional support in setting retries.
*/
@Generated("by gapic-generator-java")
public class TopicAdminSettings extends ClientSettings {
@@ -206,7 +219,6 @@ public static TransportChannelProvider defaultTransportChannelProvider() {
return PublisherStubSettings.defaultTransportChannelProvider();
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() {
return PublisherStubSettings.defaultApiClientHeaderProviderBuilder();
}
@@ -217,7 +229,6 @@ public static Builder newBuilder() {
}
/** Returns a new REST builder for this class. */
- @BetaApi
public static Builder newHttpJsonBuilder() {
return Builder.createHttpJsonDefault();
}
@@ -259,7 +270,6 @@ private static Builder createDefault() {
return new Builder(PublisherStubSettings.newBuilder());
}
- @BetaApi
private static Builder createHttpJsonDefault() {
return new Builder(PublisherStubSettings.newHttpJsonBuilder());
}
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Waiter.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Waiter.java
index e22125fee..7221d5144 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Waiter.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Waiter.java
@@ -16,6 +16,7 @@
package com.google.cloud.pubsub.v1;
+import com.google.api.core.ApiClock;
import com.google.api.core.InternalApi;
/**
@@ -54,6 +55,32 @@ public synchronized void waitComplete() {
}
}
+ public synchronized boolean tryWait(long timeoutMilliseconds, ApiClock clock) {
+ long startTime = clock.millisTime();
+ long remainingMilliseconds = timeoutMilliseconds;
+ boolean interrupted = false;
+ boolean completedWait = true;
+ try {
+ while (pendingCount > 0) {
+ if (remainingMilliseconds <= 0) {
+ completedWait = false;
+ break;
+ }
+ try {
+ wait(remainingMilliseconds);
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ remainingMilliseconds = timeoutMilliseconds - (clock.millisTime() - startTime);
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return completedWait;
+ }
+
@InternalApi
public int pendingCount() {
return pendingCount;
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/package-info.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/package-info.java
index 5e73e3a64..28c492a15 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/package-info.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherCallableFactory.java
index 60af80164..c6ed49480 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java
index d4c26515d..df360653c 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcPublisherStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -68,6 +68,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/CreateTopic")
.setRequestMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor updateTopicMethodDescriptor =
@@ -76,6 +77,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/UpdateTopic")
.setRequestMarshaller(ProtoUtils.marshaller(UpdateTopicRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor publishMethodDescriptor =
@@ -84,6 +86,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/Publish")
.setRequestMarshaller(ProtoUtils.marshaller(PublishRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(PublishResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getTopicMethodDescriptor =
@@ -92,6 +95,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/GetTopic")
.setRequestMarshaller(ProtoUtils.marshaller(GetTopicRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Topic.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -101,6 +105,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/ListTopics")
.setRequestMarshaller(ProtoUtils.marshaller(ListTopicsRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(ListTopicsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor<
@@ -114,6 +119,7 @@ public class GrpcPublisherStub extends PublisherStub {
ProtoUtils.marshaller(ListTopicSubscriptionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListTopicSubscriptionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -125,6 +131,7 @@ public class GrpcPublisherStub extends PublisherStub {
ProtoUtils.marshaller(ListTopicSnapshotsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListTopicSnapshotsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor deleteTopicMethodDescriptor =
@@ -133,6 +140,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.pubsub.v1.Publisher/DeleteTopic")
.setRequestMarshaller(ProtoUtils.marshaller(DeleteTopicRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -144,6 +152,7 @@ public class GrpcPublisherStub extends PublisherStub {
ProtoUtils.marshaller(DetachSubscriptionRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(DetachSubscriptionResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor setIamPolicyMethodDescriptor =
@@ -152,6 +161,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.iam.v1.IAMPolicy/SetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(SetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getIamPolicyMethodDescriptor =
@@ -160,6 +170,7 @@ public class GrpcPublisherStub extends PublisherStub {
.setFullMethodName("google.iam.v1.IAMPolicy/GetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(GetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -171,6 +182,7 @@ public class GrpcPublisherStub extends PublisherStub {
ProtoUtils.marshaller(TestIamPermissionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(TestIamPermissionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private final UnaryCallable createTopicCallable;
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceCallableFactory.java
index b7ad8cab4..c1cce2d8e 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java
index cbaf6a608..592a17bf5 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSchemaServiceStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -68,6 +68,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.pubsub.v1.SchemaService/CreateSchema")
.setRequestMarshaller(ProtoUtils.marshaller(CreateSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Schema.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getSchemaMethodDescriptor =
@@ -76,6 +77,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.pubsub.v1.SchemaService/GetSchema")
.setRequestMarshaller(ProtoUtils.marshaller(GetSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Schema.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -86,6 +88,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setRequestMarshaller(ProtoUtils.marshaller(ListSchemasRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListSchemasResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -97,6 +100,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
ProtoUtils.marshaller(ListSchemaRevisionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListSchemaRevisionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor commitSchemaMethodDescriptor =
@@ -105,6 +109,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.pubsub.v1.SchemaService/CommitSchema")
.setRequestMarshaller(ProtoUtils.marshaller(CommitSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Schema.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -115,6 +120,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setRequestMarshaller(
ProtoUtils.marshaller(RollbackSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Schema.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -125,6 +131,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setRequestMarshaller(
ProtoUtils.marshaller(DeleteSchemaRevisionRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Schema.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor deleteSchemaMethodDescriptor =
@@ -133,6 +140,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.pubsub.v1.SchemaService/DeleteSchema")
.setRequestMarshaller(ProtoUtils.marshaller(DeleteSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -144,6 +152,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
ProtoUtils.marshaller(ValidateSchemaRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ValidateSchemaResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -155,6 +164,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
ProtoUtils.marshaller(ValidateMessageRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ValidateMessageResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor setIamPolicyMethodDescriptor =
@@ -163,6 +173,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.iam.v1.IAMPolicy/SetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(SetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getIamPolicyMethodDescriptor =
@@ -171,6 +182,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
.setFullMethodName("google.iam.v1.IAMPolicy/GetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(GetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -182,6 +194,7 @@ public class GrpcSchemaServiceStub extends SchemaServiceStub {
ProtoUtils.marshaller(TestIamPermissionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(TestIamPermissionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private final UnaryCallable createSchemaCallable;
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberCallableFactory.java
index 27f99f671..fe083befe 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java
index b3651167c..8c08d2ad3 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/GrpcSubscriberStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -77,6 +77,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.pubsub.v1.Subscriber/CreateSubscription")
.setRequestMarshaller(ProtoUtils.marshaller(Subscription.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Subscription.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -87,6 +88,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(GetSubscriptionRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Subscription.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -97,6 +99,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(UpdateSubscriptionRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Subscription.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -108,6 +111,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
ProtoUtils.marshaller(ListSubscriptionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListSubscriptionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -118,6 +122,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(DeleteSubscriptionRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -128,6 +133,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(ModifyAckDeadlineRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor acknowledgeMethodDescriptor =
@@ -136,6 +142,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.pubsub.v1.Subscriber/Acknowledge")
.setRequestMarshaller(ProtoUtils.marshaller(AcknowledgeRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor pullMethodDescriptor =
@@ -144,6 +151,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.pubsub.v1.Subscriber/Pull")
.setRequestMarshaller(ProtoUtils.marshaller(PullRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(PullResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -155,6 +163,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
ProtoUtils.marshaller(StreamingPullRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(StreamingPullResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -165,6 +174,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(ModifyPushConfigRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getSnapshotMethodDescriptor =
@@ -173,6 +183,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.pubsub.v1.Subscriber/GetSnapshot")
.setRequestMarshaller(ProtoUtils.marshaller(GetSnapshotRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Snapshot.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -184,6 +195,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
ProtoUtils.marshaller(ListSnapshotsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(ListSnapshotsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -194,6 +206,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(CreateSnapshotRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Snapshot.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -204,6 +217,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(UpdateSnapshotRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Snapshot.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -214,6 +228,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setRequestMarshaller(
ProtoUtils.marshaller(DeleteSnapshotRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor seekMethodDescriptor =
@@ -222,6 +237,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.pubsub.v1.Subscriber/Seek")
.setRequestMarshaller(ProtoUtils.marshaller(SeekRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(SeekResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor setIamPolicyMethodDescriptor =
@@ -230,6 +246,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.iam.v1.IAMPolicy/SetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(SetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor getIamPolicyMethodDescriptor =
@@ -238,6 +255,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
.setFullMethodName("google.iam.v1.IAMPolicy/GetIamPolicy")
.setRequestMarshaller(ProtoUtils.marshaller(GetIamPolicyRequest.getDefaultInstance()))
.setResponseMarshaller(ProtoUtils.marshaller(Policy.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private static final MethodDescriptor
@@ -249,6 +267,7 @@ public class GrpcSubscriberStub extends SubscriberStub {
ProtoUtils.marshaller(TestIamPermissionsRequest.getDefaultInstance()))
.setResponseMarshaller(
ProtoUtils.marshaller(TestIamPermissionsResponse.getDefaultInstance()))
+ .setSampledToLocalTracing(true)
.build();
private final UnaryCallable createSubscriptionCallable;
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherCallableFactory.java
index cd5b6e6f2..8a3a1c577 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -16,7 +16,6 @@
package com.google.cloud.pubsub.v1.stub;
-import com.google.api.core.BetaApi;
import com.google.api.gax.httpjson.HttpJsonCallSettings;
import com.google.api.gax.httpjson.HttpJsonCallableFactory;
import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
@@ -41,7 +40,6 @@
* This class is for advanced usage.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonPublisherCallableFactory
implements HttpJsonStubCallableFactory {
@@ -73,8 +71,6 @@ public UnaryCallable createBatchingCa
httpJsonCallSettings, callSettings, clientContext);
}
- @BetaApi(
- "The surface for long-running operations is not stable yet and may change in the future.")
@Override
public
OperationCallable createOperationCallable(
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherStub.java
index 5ae0dfc9e..fb668a667 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonPublisherStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -20,7 +20,6 @@
import static com.google.cloud.pubsub.v1.TopicAdminClient.ListTopicSubscriptionsPagedResponse;
import static com.google.cloud.pubsub.v1.TopicAdminClient.ListTopicsPagedResponse;
-import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.gax.core.BackgroundResource;
import com.google.api.gax.core.BackgroundResourceAggregation;
@@ -69,7 +68,6 @@
* This class is for advanced usage and reflects the underlying API directly.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonPublisherStub extends PublisherStub {
private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build();
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceCallableFactory.java
index c1db412c1..14136bdc5 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -16,7 +16,6 @@
package com.google.cloud.pubsub.v1.stub;
-import com.google.api.core.BetaApi;
import com.google.api.gax.httpjson.HttpJsonCallSettings;
import com.google.api.gax.httpjson.HttpJsonCallableFactory;
import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
@@ -41,7 +40,6 @@
*
This class is for advanced usage.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonSchemaServiceCallableFactory
implements HttpJsonStubCallableFactory {
@@ -73,8 +71,6 @@ public UnaryCallable createBatchingCa
httpJsonCallSettings, callSettings, clientContext);
}
- @BetaApi(
- "The surface for long-running operations is not stable yet and may change in the future.")
@Override
public
OperationCallable createOperationCallable(
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceStub.java
index 186405096..8816b63ad 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSchemaServiceStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -19,7 +19,6 @@
import static com.google.cloud.pubsub.v1.SchemaServiceClient.ListSchemaRevisionsPagedResponse;
import static com.google.cloud.pubsub.v1.SchemaServiceClient.ListSchemasPagedResponse;
-import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.gax.core.BackgroundResource;
import com.google.api.gax.core.BackgroundResourceAggregation;
@@ -69,7 +68,6 @@
* This class is for advanced usage and reflects the underlying API directly.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonSchemaServiceStub extends SchemaServiceStub {
private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build();
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberCallableFactory.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberCallableFactory.java
index 7acbff90f..336a8bdef 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberCallableFactory.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberCallableFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -16,7 +16,6 @@
package com.google.cloud.pubsub.v1.stub;
-import com.google.api.core.BetaApi;
import com.google.api.gax.httpjson.HttpJsonCallSettings;
import com.google.api.gax.httpjson.HttpJsonCallableFactory;
import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
@@ -41,7 +40,6 @@
*
This class is for advanced usage.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonSubscriberCallableFactory
implements HttpJsonStubCallableFactory {
@@ -73,8 +71,6 @@ public UnaryCallable createBatchingCa
httpJsonCallSettings, callSettings, clientContext);
}
- @BetaApi(
- "The surface for long-running operations is not stable yet and may change in the future.")
@Override
public
OperationCallable createOperationCallable(
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberStub.java
index 010a08bac..3b6a28ee6 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/HttpJsonSubscriberStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -19,7 +19,6 @@
import static com.google.cloud.pubsub.v1.SubscriptionAdminClient.ListSnapshotsPagedResponse;
import static com.google.cloud.pubsub.v1.SubscriptionAdminClient.ListSubscriptionsPagedResponse;
-import com.google.api.core.BetaApi;
import com.google.api.core.InternalApi;
import com.google.api.gax.core.BackgroundResource;
import com.google.api.gax.core.BackgroundResourceAggregation;
@@ -77,7 +76,6 @@
* This class is for advanced usage and reflects the underlying API directly.
*/
@Generated("by gapic-generator-java")
-@BetaApi
public class HttpJsonSubscriberStub extends SubscriberStub {
private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build();
@@ -1225,7 +1223,8 @@ public UnaryCallable getIamPolicyCallable() {
public BidiStreamingCallable
streamingPullCallable() {
throw new UnsupportedOperationException(
- "Not implemented: streamingPullCallable(). REST transport is not implemented for this method yet.");
+ "Not implemented: streamingPullCallable(). REST transport is not implemented for this"
+ + " method yet.");
}
@Override
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStub.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStub.java
index 5b8ed6112..1d8945a23 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStub.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java
index f3c495688..8f039bbe9 100644
--- a/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java
+++ b/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -23,6 +23,7 @@
import com.google.api.core.ApiFunction;
import com.google.api.core.ApiFuture;
import com.google.api.core.BetaApi;
+import com.google.api.core.ObsoleteApi;
import com.google.api.gax.batching.BatchingSettings;
import com.google.api.gax.batching.FlowControlSettings;
import com.google.api.gax.batching.FlowController;
@@ -78,11 +79,11 @@
import com.google.pubsub.v1.Topic;
import com.google.pubsub.v1.UpdateTopicRequest;
import java.io.IOException;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.Generated;
-import org.threeten.bp.Duration;
// AUTO-GENERATED DOCUMENTATION AND CLASS.
/**
@@ -99,7 +100,9 @@
* The builder of this class is recursive, so contained classes are themselves builders. When
* build() is called, the tree of builders is called to create the complete settings object.
*
- *
For example, to set the total timeout of createTopic to 30 seconds:
+ *
For example, to set the
+ * [RetrySettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.retrying.RetrySettings)
+ * of createTopic:
*
*
{@code
* // This snippet has been automatically generated and should be regarded as a code template only.
@@ -115,10 +118,21 @@
* .createTopicSettings()
* .getRetrySettings()
* .toBuilder()
- * .setTotalTimeout(Duration.ofSeconds(30))
+ * .setInitialRetryDelayDuration(Duration.ofSeconds(1))
+ * .setInitialRpcTimeoutDuration(Duration.ofSeconds(5))
+ * .setMaxAttempts(5)
+ * .setMaxRetryDelayDuration(Duration.ofSeconds(30))
+ * .setMaxRpcTimeoutDuration(Duration.ofSeconds(60))
+ * .setRetryDelayMultiplier(1.3)
+ * .setRpcTimeoutMultiplier(1.5)
+ * .setTotalTimeoutDuration(Duration.ofSeconds(300))
* .build());
* PublisherStubSettings topicAdminSettings = topicAdminSettingsBuilder.build();
* }
+ *
+ * Please refer to the [Client Side Retry
+ * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
+ * additional support in setting retries.
*/
@Generated("by gapic-generator-java")
public class PublisherStubSettings extends StubSettings {
@@ -181,9 +195,7 @@ public String extractNextToken(ListTopicsResponse payload) {
@Override
public Iterable extractResources(ListTopicsResponse payload) {
- return payload.getTopicsList() == null
- ? ImmutableList.of()
- : payload.getTopicsList();
+ return payload.getTopicsList();
}
};
@@ -223,9 +235,7 @@ public String extractNextToken(ListTopicSubscriptionsResponse payload) {
@Override
public Iterable extractResources(ListTopicSubscriptionsResponse payload) {
- return payload.getSubscriptionsList() == null
- ? ImmutableList.of()
- : payload.getSubscriptionsList();
+ return payload.getSubscriptionsList();
}
};
@@ -262,9 +272,7 @@ public String extractNextToken(ListTopicSnapshotsResponse payload) {
@Override
public Iterable extractResources(ListTopicSnapshotsResponse payload) {
- return payload.getSnapshotsList() == null
- ? ImmutableList.of()
- : payload.getSnapshotsList();
+ return payload.getSnapshotsList();
}
};
@@ -492,6 +500,7 @@ public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuild
}
/** Returns the default service endpoint. */
+ @ObsoleteApi("Use getEndpoint() instead")
public static String getDefaultEndpoint() {
return "pubsub.googleapis.com:443";
}
@@ -530,7 +539,6 @@ public static TransportChannelProvider defaultTransportChannelProvider() {
return defaultGrpcTransportProviderBuilder().build();
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(PublisherStubSettings.class))
@@ -538,7 +546,6 @@ public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProvider
GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion());
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(PublisherStubSettings.class))
@@ -648,35 +655,35 @@ public static class Builder extends StubSettings.BuilderThe builder of this class is recursive, so contained classes are themselves builders. When
* build() is called, the tree of builders is called to create the complete settings object.
*
- * For example, to set the total timeout of createSchema to 30 seconds:
+ *
For example, to set the
+ * [RetrySettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.retrying.RetrySettings)
+ * of createSchema:
*
*
{@code
* // This snippet has been automatically generated and should be regarded as a code template only.
@@ -106,10 +109,21 @@
* .createSchemaSettings()
* .getRetrySettings()
* .toBuilder()
- * .setTotalTimeout(Duration.ofSeconds(30))
+ * .setInitialRetryDelayDuration(Duration.ofSeconds(1))
+ * .setInitialRpcTimeoutDuration(Duration.ofSeconds(5))
+ * .setMaxAttempts(5)
+ * .setMaxRetryDelayDuration(Duration.ofSeconds(30))
+ * .setMaxRpcTimeoutDuration(Duration.ofSeconds(60))
+ * .setRetryDelayMultiplier(1.3)
+ * .setRpcTimeoutMultiplier(1.5)
+ * .setTotalTimeoutDuration(Duration.ofSeconds(300))
* .build());
* SchemaServiceStubSettings schemaServiceSettings = schemaServiceSettingsBuilder.build();
* }
+ *
+ * Please refer to the [Client Side Retry
+ * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
+ * additional support in setting retries.
*/
@Generated("by gapic-generator-java")
public class SchemaServiceStubSettings extends StubSettings {
@@ -170,9 +184,7 @@ public String extractNextToken(ListSchemasResponse payload) {
@Override
public Iterable extractResources(ListSchemasResponse payload) {
- return payload.getSchemasList() == null
- ? ImmutableList.of()
- : payload.getSchemasList();
+ return payload.getSchemasList();
}
};
@@ -210,9 +222,7 @@ public String extractNextToken(ListSchemaRevisionsResponse payload) {
@Override
public Iterable extractResources(ListSchemaRevisionsResponse payload) {
- return payload.getSchemasList() == null
- ? ImmutableList.of()
- : payload.getSchemasList();
+ return payload.getSchemasList();
}
};
@@ -352,6 +362,7 @@ public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuild
}
/** Returns the default service endpoint. */
+ @ObsoleteApi("Use getEndpoint() instead")
public static String getDefaultEndpoint() {
return "pubsub.googleapis.com:443";
}
@@ -390,7 +401,6 @@ public static TransportChannelProvider defaultTransportChannelProvider() {
return defaultGrpcTransportProviderBuilder().build();
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken(
@@ -399,7 +409,6 @@ public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProvider
GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion());
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken(
@@ -497,13 +506,13 @@ public static class Builder extends StubSettings.BuilderThe builder of this class is recursive, so contained classes are themselves builders. When
* build() is called, the tree of builders is called to create the complete settings object.
*
- * For example, to set the total timeout of createSubscription to 30 seconds:
+ *
For example, to set the
+ * [RetrySettings](https://cloud.google.com/java/docs/reference/gax/latest/com.google.api.gax.retrying.RetrySettings)
+ * of createSubscription:
*
*
{@code
* // This snippet has been automatically generated and should be regarded as a code template only.
@@ -114,10 +117,21 @@
* .createSubscriptionSettings()
* .getRetrySettings()
* .toBuilder()
- * .setTotalTimeout(Duration.ofSeconds(30))
+ * .setInitialRetryDelayDuration(Duration.ofSeconds(1))
+ * .setInitialRpcTimeoutDuration(Duration.ofSeconds(5))
+ * .setMaxAttempts(5)
+ * .setMaxRetryDelayDuration(Duration.ofSeconds(30))
+ * .setMaxRpcTimeoutDuration(Duration.ofSeconds(60))
+ * .setRetryDelayMultiplier(1.3)
+ * .setRpcTimeoutMultiplier(1.5)
+ * .setTotalTimeoutDuration(Duration.ofSeconds(300))
* .build());
* SubscriberStubSettings subscriptionAdminSettings = subscriptionAdminSettingsBuilder.build();
* }
+ *
+ * Please refer to the [Client Side Retry
+ * Guide](https://github.com/googleapis/google-cloud-java/blob/main/docs/client_retries.md) for
+ * additional support in setting retries.
*/
@Generated("by gapic-generator-java")
public class SubscriberStubSettings extends StubSettings {
@@ -189,9 +203,7 @@ public String extractNextToken(ListSubscriptionsResponse payload) {
@Override
public Iterable extractResources(ListSubscriptionsResponse payload) {
- return payload.getSubscriptionsList() == null
- ? ImmutableList.of()
- : payload.getSubscriptionsList();
+ return payload.getSubscriptionsList();
}
};
@@ -225,9 +237,7 @@ public String extractNextToken(ListSnapshotsResponse payload) {
@Override
public Iterable extractResources(ListSnapshotsResponse payload) {
- return payload.getSnapshotsList() == null
- ? ImmutableList.of()
- : payload.getSnapshotsList();
+ return payload.getSnapshotsList();
}
};
@@ -397,6 +407,7 @@ public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuild
}
/** Returns the default service endpoint. */
+ @ObsoleteApi("Use getEndpoint() instead")
public static String getDefaultEndpoint() {
return "pubsub.googleapis.com:443";
}
@@ -434,7 +445,6 @@ public static TransportChannelProvider defaultTransportChannelProvider() {
return defaultGrpcTransportProviderBuilder().build();
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken(
@@ -443,7 +453,6 @@ public static ApiClientHeaderProvider.Builder defaultGrpcApiClientHeaderProvider
GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion());
}
- @BetaApi("The surface for customizing headers is not stable yet and may change in the future.")
public static ApiClientHeaderProvider.Builder defaultHttpJsonApiClientHeaderProviderBuilder() {
return ApiClientHeaderProvider.newBuilder()
.setGeneratedLibToken(
@@ -575,46 +584,46 @@ public static class Builder extends StubSettings.Builder schedule(Runnable command, long delay, TimeUnit unit) {
return schedulePendingCallable(
new PendingCallable<>(
- Duration.ofMillis(unit.toMillis(delay)), command, PendingCallableType.NORMAL));
+ Duration.ofMillis(unit.toMillis(delay)), command, null, PendingCallableType.NORMAL));
}
@Override
public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
return schedulePendingCallable(
new PendingCallable<>(
- Duration.ofMillis(unit.toMillis(delay)), callable, PendingCallableType.NORMAL));
+ Duration.ofMillis(unit.toMillis(delay)), callable, null, PendingCallableType.NORMAL));
}
@Override
@@ -72,6 +72,7 @@ public ScheduledFuture> scheduleAtFixedRate(
new PendingCallable<>(
Duration.ofMillis(unit.toMillis(initialDelay)),
command,
+ Duration.ofMillis(unit.toMillis(period)),
PendingCallableType.FIXED_RATE));
}
@@ -82,6 +83,7 @@ public ScheduledFuture> scheduleWithFixedDelay(
new PendingCallable<>(
Duration.ofMillis(unit.toMillis(initialDelay)),
command,
+ Duration.ofMillis(unit.toMillis(delay)),
PendingCallableType.FIXED_DELAY));
}
@@ -212,13 +214,15 @@ enum PendingCallableType {
class PendingCallable implements Comparable> {
Instant creationTime = Instant.ofEpochMilli(clock.millisTime());
Duration delay;
+ Duration period;
Callable pendingCallable;
SettableFuture future = SettableFuture.create();
AtomicBoolean cancelled = new AtomicBoolean(false);
AtomicBoolean done = new AtomicBoolean(false);
PendingCallableType type;
- PendingCallable(Duration delay, final Runnable runnable, PendingCallableType type) {
+ PendingCallable(
+ Duration delay, final Runnable runnable, Duration period, PendingCallableType type) {
pendingCallable =
new Callable() {
@Override
@@ -229,12 +233,15 @@ public T call() {
};
this.type = type;
this.delay = delay;
+ this.period = period;
}
- PendingCallable(Duration delay, Callable callable, PendingCallableType type) {
+ PendingCallable(
+ Duration delay, Callable callable, Duration period, PendingCallableType type) {
pendingCallable = callable;
this.type = type;
this.delay = delay;
+ this.period = period;
}
private Instant getScheduledTime() {
@@ -305,10 +312,12 @@ T call() {
break;
case FIXED_DELAY:
this.creationTime = Instant.ofEpochMilli(clock.millisTime());
+ this.delay = period;
schedulePendingCallable(this);
break;
case FIXED_RATE:
this.creationTime = this.creationTime.plus(delay);
+ this.delay = period;
schedulePendingCallable(this);
break;
default:
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/FakeSubscriberServiceImpl.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/FakeSubscriberServiceImpl.java
index 173248041..3b2bd2f5d 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/FakeSubscriberServiceImpl.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/FakeSubscriberServiceImpl.java
@@ -24,6 +24,7 @@
import com.google.pubsub.v1.PublisherGrpc.PublisherImplBase;
import com.google.pubsub.v1.PullRequest;
import com.google.pubsub.v1.PullResponse;
+import com.google.pubsub.v1.ReceivedMessage;
import com.google.pubsub.v1.StreamingPullRequest;
import com.google.pubsub.v1.StreamingPullResponse;
import com.google.pubsub.v1.SubscriberGrpc.SubscriberImplBase;
@@ -247,8 +248,26 @@ public void modifyAckDeadline(
responseObserver.onCompleted();
}
+ public void sendMessages(int numMessages) throws InterruptedException {
+ waitForRegisteredSubscription();
+ synchronized (openedStreams) {
+ waitForOpenedStreams(1);
+ Stream stream = openedStreams.get(getAndAdvanceCurrentStream());
+ StreamingPullResponse.Builder response = StreamingPullResponse.newBuilder();
+ for (int i = 0; i < numMessages; i++) {
+ response.addReceivedMessages(
+ ReceivedMessage.newBuilder()
+ .setAckId("ackid" + i)
+ .setMessage(
+ com.google.pubsub.v1.PubsubMessage.newBuilder().setMessageId("id" + i).build())
+ .build());
+ }
+ stream.responseObserver.onNext(response.build());
+ }
+ }
+
public void sendError(Throwable error) throws InterruptedException {
- waitForRegistedSubscription();
+ waitForRegisteredSubscription();
synchronized (openedStreams) {
waitForOpenedStreams(1);
Stream stream = openedStreams.get(getAndAdvanceCurrentStream());
@@ -257,7 +276,7 @@ public void sendError(Throwable error) throws InterruptedException {
}
}
- public String waitForRegistedSubscription() throws InterruptedException {
+ public String waitForRegisteredSubscription() throws InterruptedException {
synchronized (subscriptionInitialized) {
while (!subscriptionInitialized.get()) {
subscriptionInitialized.wait();
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MessageDispatcherTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MessageDispatcherTest.java
index c608ee8d5..1285fadd5 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MessageDispatcherTest.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MessageDispatcherTest.java
@@ -18,6 +18,9 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import com.google.api.gax.batching.FlowController;
@@ -26,15 +29,17 @@
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.ReceivedMessage;
+import java.time.Duration;
import java.util.*;
import java.util.concurrent.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import org.threeten.bp.Duration;
public class MessageDispatcherTest {
+ private static final String MOCK_SUBSCRIPTION_NAME =
+ "projects/MOCK-PROJECT/subscriptions/MOCK-SUBSCRIPTION";
private static final ByteString MESSAGE_DATA = ByteString.copyFromUtf8("message-data");
private static final int DELIVERY_INFO_COUNT = 3;
private static final String ACK_ID = "ACK-ID";
@@ -462,6 +467,7 @@ public void testAckExtensionDefaultsExactlyOnceDeliveryDisabledThenEnabled() {
.setMinDurationPerAckExtensionDefaultUsed(true)
.setMaxDurationPerAckExtension(Subscriber.DEFAULT_MAX_ACK_DEADLINE_EXTENSION)
.setMaxDurationPerAckExtensionDefaultUsed(true)
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
.build();
// ExactlyOnceDeliveryEnabled is turned off by default
@@ -494,6 +500,7 @@ public void testAckExtensionDefaultsExactlyOnceDeliveryEnabledThenDisabled() {
.setMinDurationPerAckExtensionDefaultUsed(true)
.setMaxDurationPerAckExtension(Subscriber.DEFAULT_MIN_ACK_DEADLINE_EXTENSION)
.setMaxDurationPerAckExtensionDefaultUsed(true)
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
.build();
// This would normally be set from the streaming pull response in the
@@ -605,6 +612,7 @@ public void testAckExtensionCustomMinExactlyOnceDeliveryDisabledThenEnabled() {
.setMinDurationPerAckExtensionDefaultUsed(false)
.setMaxDurationPerAckExtension(Subscriber.DEFAULT_MIN_ACK_DEADLINE_EXTENSION)
.setMaxDurationPerAckExtensionDefaultUsed(true)
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
.build();
// ExactlyOnceDeliveryEnabled is turned off by default
@@ -634,6 +642,7 @@ public void testAckExtensionCustomMaxExactlyOnceDeliveryDisabledThenEnabled() {
.setMinDurationPerAckExtensionDefaultUsed(true)
.setMaxDurationPerAckExtension(Duration.ofSeconds(customMaxSeconds))
.setMaxDurationPerAckExtensionDefaultUsed(false)
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
.build();
// ExactlyOnceDeliveryEnabled is turned off by default
@@ -704,11 +713,241 @@ private MessageDispatcher getMessageDispatcherFromBuilder(
.setAckLatencyDistribution(mock(Distribution.class))
.setFlowController(mock(FlowController.class))
.setExecutor(executor)
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
.setSystemExecutor(systemExecutor)
.setApiClock(clock)
+ .setSubscriberShutdownSettings(SubscriberShutdownSettings.newBuilder().build())
.build();
messageDispatcher.setMessageDeadlineSeconds(MIN_ACK_DEADLINE_SECONDS);
return messageDispatcher;
}
+
+ private MessageDispatcher getMessageDispatcherFromBuilder(
+ MessageDispatcher.Builder builder, SubscriberShutdownSettings shutdownSettings) {
+ MessageDispatcher messageDispatcher =
+ builder
+ .setAckProcessor(mockAckProcessor)
+ .setAckExpirationPadding(ACK_EXPIRATION_PADDING_DEFAULT)
+ .setMaxAckExtensionPeriod(MAX_ACK_EXTENSION_PERIOD)
+ .setMinDurationPerAckExtension(Subscriber.DEFAULT_MIN_ACK_DEADLINE_EXTENSION)
+ .setMinDurationPerAckExtensionDefaultUsed(true)
+ .setMaxDurationPerAckExtension(Subscriber.DEFAULT_MAX_ACK_DEADLINE_EXTENSION)
+ .setMaxDurationPerAckExtensionDefaultUsed(true)
+ .setAckLatencyDistribution(mock(Distribution.class))
+ .setFlowController(mock(FlowController.class))
+ .setExecutor(MoreExecutors.newDirectExecutorService())
+ .setSubscriptionName(MOCK_SUBSCRIPTION_NAME)
+ .setSystemExecutor(systemExecutor)
+ .setApiClock(clock)
+ .setSubscriberShutdownSettings(shutdownSettings)
+ .build();
+
+ messageDispatcher.setMessageDeadlineSeconds(MIN_ACK_DEADLINE_SECONDS);
+ return messageDispatcher;
+ }
+
+ @Test
+ public void testStop_waitForProcessing_indefinite() throws Exception {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.WAIT_FOR_PROCESSING)
+ .setTimeout(Duration.ofSeconds(-1))
+ .build();
+ MessageDispatcher dispatcher =
+ getMessageDispatcherFromBuilder(
+ MessageDispatcher.newBuilder(messageReceiver), shutdownSettings);
+
+ dispatcher.processReceivedMessages(Collections.singletonList(TEST_MESSAGE));
+
+ Thread stopThread = new Thread(dispatcher::stop);
+ stopThread.start();
+
+ // Wait for the stop thread to block on the waiter.
+ Thread.sleep(100);
+ assertTrue(stopThread.isAlive());
+
+ // Ack the message, which should allow the stop thread to complete.
+ consumers.take().ack();
+
+ List ackRequestDataList = new ArrayList();
+ AckRequestData ackRequestData = AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build();
+ ackRequestDataList.add(ackRequestData);
+
+ stopThread.join();
+ assertFalse(stopThread.isAlive());
+
+ verify(mockAckProcessor, times(1))
+ .sendAckOperations(
+ argThat(new CustomArgumentMatchers.AckRequestDataListMatcher(ackRequestDataList)));
+ }
+
+ @Test
+ public void testStop_waitForProcessing_withTimeout_success() {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.WAIT_FOR_PROCESSING)
+ .setTimeout(Duration.ofSeconds(5))
+ .build();
+ MessageDispatcher dispatcher =
+ getMessageDispatcherFromBuilder(
+ MessageDispatcher.newBuilder(messageReceiver), shutdownSettings);
+
+ dispatcher.processReceivedMessages(Collections.singletonList(TEST_MESSAGE));
+
+ Thread stopThread = new Thread(dispatcher::stop);
+ stopThread.start();
+
+ // Ack the message before the timeout expires.
+ try {
+ consumers.take().ack();
+ } catch (InterruptedException e) {
+ fail("Interrupted while taking consumer");
+ }
+
+ try {
+ stopThread.join(1000);
+ } catch (InterruptedException e) {
+ fail("Interrupted while joining stop thread");
+ }
+
+ List ackRequestDataList = new ArrayList();
+ AckRequestData ackRequestData = AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build();
+ ackRequestDataList.add(ackRequestData);
+
+ verify(mockAckProcessor, times(1))
+ .sendAckOperations(
+ argThat(new CustomArgumentMatchers.AckRequestDataListMatcher(ackRequestDataList)));
+ assertFalse(stopThread.isAlive());
+ }
+
+ @Test
+ public void testStop_waitForProcessing_withTimeout_nackWithOneSecondLeft() {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.WAIT_FOR_PROCESSING)
+ .setTimeout(Duration.ofSeconds(2))
+ .build();
+ MessageDispatcher dispatcher =
+ getMessageDispatcherFromBuilder(
+ MessageDispatcher.newBuilder(messageReceiver), shutdownSettings);
+
+ dispatcher.processReceivedMessages(Collections.singletonList(TEST_MESSAGE));
+ Thread stopThread = new Thread(dispatcher::stop);
+ stopThread.start();
+
+ // Wait for the stop thread to block on the waiter.
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ fail("Interrupted while sleeping");
+ }
+
+ clock.advance(1500, TimeUnit.MILLISECONDS);
+
+ try {
+ stopThread.join();
+ } catch (InterruptedException e) {
+ fail("Interrupted while joining stop thread");
+ }
+ // Assert expected behavior
+ List modackRequestDataList = new ArrayList();
+ modackRequestDataList.add(
+ new ModackRequestData(0, AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build()));
+
+ verify(mockAckProcessor, times(1))
+ .sendModackOperations(
+ argThat(
+ new CustomArgumentMatchers.ModackRequestDataListMatcher(modackRequestDataList)));
+ verify(mockAckProcessor, times(1))
+ .sendAckOperations(
+ argThat(new CustomArgumentMatchers.AckRequestDataListMatcher(Collections.emptyList())));
+ }
+
+ @Test
+ public void testStop_nackImmediately() {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.NACK_IMMEDIATELY)
+ .build();
+ MessageDispatcher dispatcher =
+ getMessageDispatcherFromBuilder(
+ MessageDispatcher.newBuilder(messageReceiver), shutdownSettings);
+
+ dispatcher.processReceivedMessages(Collections.singletonList(TEST_MESSAGE));
+ dispatcher.stop();
+
+ // Assert expected behavior
+ List modackRequestDataList = new ArrayList();
+ modackRequestDataList.add(
+ new ModackRequestData(0, AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build()));
+
+ verify(mockAckProcessor, times(1))
+ .sendModackOperations(
+ argThat(
+ new CustomArgumentMatchers.ModackRequestDataListMatcher(modackRequestDataList)));
+ verify(mockAckProcessor, times(1))
+ .sendAckOperations(
+ argThat(new CustomArgumentMatchers.AckRequestDataListMatcher(Collections.emptyList())));
+ }
+
+ @Test
+ public void testAckDuringNackImmediatelyShutdown() throws Exception {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.NACK_IMMEDIATELY)
+ .build();
+ MessageDispatcher dispatcher =
+ getMessageDispatcherFromBuilder(
+ MessageDispatcher.newBuilder(messageReceiverWithAckResponse), shutdownSettings);
+ dispatcher.setExactlyOnceDeliveryEnabled(true);
+
+ dispatcher.processReceivedMessages(Collections.singletonList(TEST_MESSAGE));
+ dispatcher.processOutstandingOperations();
+
+ List receiptModackRequestDataList = new ArrayList();
+ AckRequestData receiptModackRequestData =
+ AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build();
+ receiptModackRequestDataList.add(
+ new ModackRequestData(MIN_ACK_DEADLINE_SECONDS, receiptModackRequestData));
+ dispatcher.notifyAckSuccess(receiptModackRequestData);
+
+ verify(mockAckProcessor, times(1))
+ .sendModackOperations(
+ argThat(
+ new CustomArgumentMatchers.ModackRequestDataListMatcher(
+ receiptModackRequestDataList)));
+
+ Thread stopThread =
+ new Thread(
+ () -> {
+ dispatcher.stop();
+ });
+ stopThread.start();
+
+ // Wait for the stop process to start.
+ while (!dispatcher.getNackImmediatelyShutdownInProgress()) {
+ Thread.sleep(1);
+ }
+
+ // Try to ack the message.
+ AckResponse reply = consumersWithResponse.take().ack().get();
+ assertThat(reply.equals(AckResponse.OTHER));
+
+ stopThread.join();
+
+ // Assert expected behavior
+ List modackRequestDataList = new ArrayList();
+ modackRequestDataList.add(
+ new ModackRequestData(0, AckRequestData.newBuilder(TEST_MESSAGE.getAckId()).build()));
+
+ // The message should have been nacked, not acked.
+ verify(mockAckProcessor, times(1))
+ .sendModackOperations(
+ argThat(
+ new CustomArgumentMatchers.ModackRequestDataListMatcher(modackRequestDataList)));
+ verify(mockAckProcessor, times(2))
+ .sendAckOperations(
+ argThat(new CustomArgumentMatchers.AckRequestDataListMatcher(Collections.emptyList())));
+ }
}
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicy.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicy.java
index c17e00ad2..ee510a051 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicy.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicyImpl.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicyImpl.java
index e18c2a7bc..f686ce75c 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicyImpl.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockIAMPolicyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisher.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisher.java
index 2a26cd59a..239ed0369 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisher.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisher.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisherImpl.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisherImpl.java
index 47cf6f416..e01c205a6 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisherImpl.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockPublisherImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -189,7 +189,8 @@ public void listTopicSubscriptions(
responseObserver.onError(
new IllegalArgumentException(
String.format(
- "Unrecognized response type %s for method ListTopicSubscriptions, expected %s or %s",
+ "Unrecognized response type %s for method ListTopicSubscriptions, expected %s or"
+ + " %s",
response == null ? "null" : response.getClass().getName(),
ListTopicSubscriptionsResponse.class.getName(),
Exception.class.getName())));
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaService.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaService.java
index 29559fa86..838d5fbc6 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaService.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaServiceImpl.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaServiceImpl.java
index 8510e1b77..71c5edb34 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaServiceImpl.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSchemaServiceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -212,7 +212,8 @@ public void deleteSchemaRevision(
responseObserver.onError(
new IllegalArgumentException(
String.format(
- "Unrecognized response type %s for method DeleteSchemaRevision, expected %s or %s",
+ "Unrecognized response type %s for method DeleteSchemaRevision, expected %s or"
+ + " %s",
response == null ? "null" : response.getClass().getName(),
Schema.class.getName(),
Exception.class.getName())));
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriber.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriber.java
index 13b54dd7a..067dcd861 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriber.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriber.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriberImpl.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriberImpl.java
index 389fc6561..cd711d2a2 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriberImpl.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/MockSubscriberImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
@@ -265,7 +265,8 @@ public void onNext(StreamingPullRequest value) {
responseObserver.onError(
new IllegalArgumentException(
String.format(
- "Unrecognized response type %s for method StreamingPull, expected %s or %s",
+ "Unrecognized response type %s for method StreamingPull, expected %s or"
+ + " %s",
response == null ? "null" : response.getClass().getName(),
StreamingPullResponse.class.getName(),
Exception.class.getName())));
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/OpenTelemetryTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/OpenTelemetryTest.java
new file mode 100644
index 000000000..52351ddef
--- /dev/null
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/OpenTelemetryTest.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright 2024 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.assertTrue;
+
+import com.google.protobuf.ByteString;
+import com.google.pubsub.v1.PubsubMessage;
+import com.google.pubsub.v1.SubscriptionName;
+import com.google.pubsub.v1.TopicName;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.sdk.testing.assertj.AttributesAssert;
+import io.opentelemetry.sdk.testing.assertj.EventDataAssert;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
+import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
+import io.opentelemetry.sdk.trace.data.LinkData;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+
+public class OpenTelemetryTest {
+ private static final TopicName FULL_TOPIC_NAME =
+ TopicName.parse("projects/test-project/topics/test-topic");
+ private static final SubscriptionName FULL_SUBSCRIPTION_NAME =
+ SubscriptionName.parse("projects/test-project/subscriptions/test-sub");
+ private static final String PROJECT_NAME = "test-project";
+ private static final String ORDERING_KEY = "abc";
+ private static final String MESSAGE_ID = "m0";
+ private static final String ACK_ID = "def";
+ private static final int DELIVERY_ATTEMPT = 1;
+ private static final int ACK_DEADLINE = 10;
+ private static final boolean EXACTLY_ONCE_ENABLED = true;
+
+ private static final String PUBLISHER_SPAN_NAME = FULL_TOPIC_NAME.getTopic() + " create";
+ private static final String PUBLISH_FLOW_CONTROL_SPAN_NAME = "publisher flow control";
+ private static final String PUBLISH_BATCHING_SPAN_NAME = "publisher batching";
+ private static final String PUBLISH_RPC_SPAN_NAME = FULL_TOPIC_NAME.getTopic() + " publish";
+ private static final String PUBLISH_START_EVENT = "publish start";
+ private static final String PUBLISH_END_EVENT = "publish end";
+
+ private static final String SUBSCRIBER_SPAN_NAME =
+ FULL_SUBSCRIPTION_NAME.getSubscription() + " subscribe";
+ private static final String SUBSCRIBE_CONCURRENCY_CONTROL_SPAN_NAME =
+ "subscriber concurrency control";
+ private static final String SUBSCRIBE_SCHEDULER_SPAN_NAME = "subscriber scheduler";
+ private static final String SUBSCRIBE_PROCESS_SPAN_NAME =
+ FULL_SUBSCRIPTION_NAME.getSubscription() + " process";
+ private static final String SUBSCRIBE_MODACK_RPC_SPAN_NAME =
+ FULL_SUBSCRIPTION_NAME.getSubscription() + " modack";
+ private static final String SUBSCRIBE_ACK_RPC_SPAN_NAME =
+ FULL_SUBSCRIPTION_NAME.getSubscription() + " ack";
+ private static final String SUBSCRIBE_NACK_RPC_SPAN_NAME =
+ FULL_SUBSCRIPTION_NAME.getSubscription() + " nack";
+
+ private static final String PROCESS_ACTION = "ack";
+ private static final String MODACK_START_EVENT = "modack start";
+ private static final String MODACK_END_EVENT = "modack end";
+ private static final String NACK_START_EVENT = "nack start";
+ private static final String NACK_END_EVENT = "nack end";
+ private static final String ACK_START_EVENT = "ack start";
+ private static final String ACK_END_EVENT = "ack end";
+
+ private static final String MESSAGING_SYSTEM_ATTR_KEY = "messaging.system";
+ private static final String MESSAGING_DESTINATION_NAME_ATTR_KEY = "messaging.destination.name";
+ private static final String CODE_FUNCTION_ATTR_KEY = "code.function";
+ private static final String MESSAGING_OPERATION_ATTR_KEY = "messaging.operation";
+ private static final String MESSAGING_BATCH_MESSAGE_COUNT_ATTR_KEY =
+ "messaging.batch.message_count";
+ private static final String MESSAGING_MESSAGE_ID_ATTR_KEY = "messaging.message.id";
+ private static final String MESSAGING_SYSTEM_VALUE = "gcp_pubsub";
+ private static final String PROJECT_ATTR_KEY = "gcp.project_id";
+ private static final String MESSAGE_SIZE_ATTR_KEY = "messaging.message.body.size";
+ private static final String ORDERING_KEY_ATTR_KEY = "messaging.gcp_pubsub.message.ordering_key";
+ private static final String ACK_DEADLINE_ATTR_KEY = "messaging.gcp_pubsub.message.ack_deadline";
+ private static final String RECEIPT_MODACK_ATTR_KEY = "messaging.gcp_pubsub.is_receipt_modack";
+ private static final String MESSAGE_ACK_ID_ATTR_KEY = "messaging.gcp_pubsub.message.ack_id";
+ private static final String MESSAGE_EXACTLY_ONCE_ATTR_KEY =
+ "messaging.gcp_pubsub.message.exactly_once_delivery";
+ private static final String MESSAGE_RESULT_ATTR_KEY = "messaging.gcp_pubsub.result";
+ private static final String MESSAGE_DELIVERY_ATTEMPT_ATTR_KEY =
+ "messaging.gcp_pubsub.message.delivery_attempt";
+
+ private static final String TRACEPARENT_ATTRIBUTE = "googclient_traceparent";
+
+ private static final OpenTelemetryRule openTelemetryTesting = OpenTelemetryRule.create();
+
+ @Test
+ public void testPublishSpansSuccess() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(getPubsubMessage(), FULL_TOPIC_NAME).build();
+ List messageWrappers = Arrays.asList(messageWrapper);
+
+ long messageSize = messageWrapper.getPubsubMessage().getData().size();
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ // Call all span start/end methods in the expected order
+ tracer.startPublisherSpan(messageWrapper);
+ tracer.startPublishFlowControlSpan(messageWrapper);
+ tracer.endPublishFlowControlSpan(messageWrapper);
+ tracer.startPublishBatchingSpan(messageWrapper);
+ tracer.endPublishBatchingSpan(messageWrapper);
+ Span publishRpcSpan = tracer.startPublishRpcSpan(FULL_TOPIC_NAME, messageWrappers);
+ tracer.endPublishRpcSpan(publishRpcSpan);
+ tracer.setPublisherMessageIdSpanAttribute(messageWrapper, MESSAGE_ID);
+ tracer.endPublisherSpan(messageWrapper);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(4, allSpans.size());
+ SpanData flowControlSpanData = allSpans.get(0);
+ SpanData batchingSpanData = allSpans.get(1);
+ SpanData publishRpcSpanData = allSpans.get(2);
+ SpanData publisherSpanData = allSpans.get(3);
+
+ SpanDataAssert flowControlSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(flowControlSpanData);
+ flowControlSpanDataAssert
+ .hasName(PUBLISH_FLOW_CONTROL_SPAN_NAME)
+ .hasParent(publisherSpanData)
+ .hasEnded();
+
+ SpanDataAssert batchingSpanDataAssert = OpenTelemetryAssertions.assertThat(batchingSpanData);
+ batchingSpanDataAssert
+ .hasName(PUBLISH_BATCHING_SPAN_NAME)
+ .hasParent(publisherSpanData)
+ .hasEnded();
+
+ // Check span data, links, and attributes for the publish RPC span
+ SpanDataAssert publishRpcSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(publishRpcSpanData);
+ publishRpcSpanDataAssert
+ .hasName(PUBLISH_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasEnded();
+
+ List publishRpcLinks = publishRpcSpanData.getLinks();
+ assertEquals(messageWrappers.size(), publishRpcLinks.size());
+ assertEquals(publisherSpanData.getSpanContext(), publishRpcLinks.get(0).getSpanContext());
+
+ assertEquals(6, publishRpcSpanData.getAttributes().size());
+ AttributesAssert publishRpcSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(publishRpcSpanData.getAttributes());
+ publishRpcSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_TOPIC_NAME.getTopic())
+ .containsEntry(PROJECT_ATTR_KEY, FULL_TOPIC_NAME.getProject())
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "publishCall")
+ .containsEntry(MESSAGING_OPERATION_ATTR_KEY, "publish")
+ .containsEntry(MESSAGING_BATCH_MESSAGE_COUNT_ATTR_KEY, messageWrappers.size());
+
+ // Check span data, events, links, and attributes for the publisher create span
+ SpanDataAssert publisherSpanDataAssert = OpenTelemetryAssertions.assertThat(publisherSpanData);
+ publisherSpanDataAssert
+ .hasName(PUBLISHER_SPAN_NAME)
+ .hasKind(SpanKind.PRODUCER)
+ .hasNoParent()
+ .hasEnded();
+
+ assertEquals(2, publisherSpanData.getEvents().size());
+ EventDataAssert startEventAssert =
+ OpenTelemetryAssertions.assertThat(publisherSpanData.getEvents().get(0));
+ startEventAssert.hasName(PUBLISH_START_EVENT);
+ EventDataAssert endEventAssert =
+ OpenTelemetryAssertions.assertThat(publisherSpanData.getEvents().get(1));
+ endEventAssert.hasName(PUBLISH_END_EVENT);
+
+ List publisherLinks = publisherSpanData.getLinks();
+ assertEquals(1, publisherLinks.size());
+ assertEquals(publishRpcSpanData.getSpanContext(), publisherLinks.get(0).getSpanContext());
+
+ assertEquals(8, publisherSpanData.getAttributes().size());
+ AttributesAssert publisherSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(publisherSpanData.getAttributes());
+ publisherSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_TOPIC_NAME.getTopic())
+ .containsEntry(PROJECT_ATTR_KEY, PROJECT_NAME)
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "publish")
+ .containsEntry(MESSAGING_OPERATION_ATTR_KEY, "create")
+ .containsEntry(ORDERING_KEY_ATTR_KEY, ORDERING_KEY)
+ .containsEntry(MESSAGE_SIZE_ATTR_KEY, messageSize)
+ .containsEntry(MESSAGING_MESSAGE_ID_ATTR_KEY, MESSAGE_ID);
+
+ // Check that the message has the attribute containing the trace context.
+ PubsubMessage message = messageWrapper.getPubsubMessage();
+ assertEquals(1, message.getAttributesMap().size());
+ assertTrue(message.containsAttributes(TRACEPARENT_ATTRIBUTE));
+ assertTrue(
+ message
+ .getAttributesOrDefault(TRACEPARENT_ATTRIBUTE, "")
+ .contains(publisherSpanData.getTraceId()));
+ assertTrue(
+ message
+ .getAttributesOrDefault(TRACEPARENT_ATTRIBUTE, "")
+ .contains(publisherSpanData.getSpanId()));
+ }
+
+ @Test
+ public void testPublishFlowControlSpanFailure() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(getPubsubMessage(), FULL_TOPIC_NAME).build();
+
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ tracer.startPublisherSpan(messageWrapper);
+ tracer.startPublishFlowControlSpan(messageWrapper);
+
+ Exception e = new Exception("test-exception");
+ tracer.setPublishFlowControlSpanException(messageWrapper, e);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(2, allSpans.size());
+ SpanData flowControlSpanData = allSpans.get(0);
+ SpanData publisherSpanData = allSpans.get(1);
+
+ SpanDataAssert flowControlSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(flowControlSpanData);
+ StatusData expectedStatus =
+ StatusData.create(StatusCode.ERROR, "Exception thrown during publish flow control.");
+ flowControlSpanDataAssert
+ .hasName(PUBLISH_FLOW_CONTROL_SPAN_NAME)
+ .hasParent(publisherSpanData)
+ .hasStatus(expectedStatus)
+ .hasException(e)
+ .hasEnded();
+
+ SpanDataAssert publisherSpanDataAssert = OpenTelemetryAssertions.assertThat(publisherSpanData);
+ publisherSpanDataAssert
+ .hasName(PUBLISHER_SPAN_NAME)
+ .hasKind(SpanKind.PRODUCER)
+ .hasNoParent()
+ .hasEnded();
+ }
+
+ @Test
+ public void testPublishRpcSpanFailure() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(getPubsubMessage(), FULL_TOPIC_NAME).build();
+
+ List messageWrappers = Arrays.asList(messageWrapper);
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ tracer.startPublisherSpan(messageWrapper);
+ Span publishRpcSpan = tracer.startPublishRpcSpan(FULL_TOPIC_NAME, messageWrappers);
+
+ Exception e = new Exception("test-exception");
+ tracer.setPublishRpcSpanException(publishRpcSpan, e);
+ tracer.endPublisherSpan(messageWrapper);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(2, allSpans.size());
+ SpanData rpcSpanData = allSpans.get(0);
+ SpanData publisherSpanData = allSpans.get(1);
+
+ SpanDataAssert rpcSpanDataAssert = OpenTelemetryAssertions.assertThat(rpcSpanData);
+ StatusData expectedStatus =
+ StatusData.create(StatusCode.ERROR, "Exception thrown on publish RPC.");
+ rpcSpanDataAssert
+ .hasName(PUBLISH_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasStatus(expectedStatus)
+ .hasException(e)
+ .hasEnded();
+
+ SpanDataAssert publisherSpanDataAssert = OpenTelemetryAssertions.assertThat(publisherSpanData);
+ publisherSpanDataAssert
+ .hasName(PUBLISHER_SPAN_NAME)
+ .hasKind(SpanKind.PRODUCER)
+ .hasNoParent()
+ .hasEnded();
+ }
+
+ @Test
+ public void testSubscribeSpansSuccess() {
+ openTelemetryTesting.clearSpans();
+
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ PubsubMessageWrapper publishMessageWrapper =
+ PubsubMessageWrapper.newBuilder(getPubsubMessage(), FULL_TOPIC_NAME).build();
+ // Initialize the Publisher span to inject the context in the message
+ tracer.startPublisherSpan(publishMessageWrapper);
+ tracer.endPublisherSpan(publishMessageWrapper);
+
+ PubsubMessage publishedMessage =
+ publishMessageWrapper.getPubsubMessage().toBuilder().setMessageId(MESSAGE_ID).build();
+ PubsubMessageWrapper subscribeMessageWrapper =
+ PubsubMessageWrapper.newBuilder(publishedMessage, FULL_SUBSCRIPTION_NAME, ACK_ID, 1)
+ .build();
+ List subscribeMessageWrappers = Arrays.asList(subscribeMessageWrapper);
+
+ long messageSize = subscribeMessageWrapper.getPubsubMessage().getData().size();
+
+ // Call all span start/end methods in the expected order
+ tracer.startSubscriberSpan(subscribeMessageWrapper, EXACTLY_ONCE_ENABLED);
+ tracer.startSubscribeConcurrencyControlSpan(subscribeMessageWrapper);
+ tracer.endSubscribeConcurrencyControlSpan(subscribeMessageWrapper);
+ tracer.startSubscribeSchedulerSpan(subscribeMessageWrapper);
+ tracer.endSubscribeSchedulerSpan(subscribeMessageWrapper);
+ tracer.startSubscribeProcessSpan(subscribeMessageWrapper);
+ tracer.endSubscribeProcessSpan(subscribeMessageWrapper, PROCESS_ACTION);
+ Span subscribeModackRpcSpan =
+ tracer.startSubscribeRpcSpan(
+ FULL_SUBSCRIPTION_NAME, "modack", subscribeMessageWrappers, ACK_DEADLINE, true);
+ tracer.endSubscribeRpcSpan(subscribeModackRpcSpan);
+ tracer.addEndRpcEvent(subscribeMessageWrapper, true, true, ACK_DEADLINE);
+ Span subscribeAckRpcSpan =
+ tracer.startSubscribeRpcSpan(
+ FULL_SUBSCRIPTION_NAME, "ack", subscribeMessageWrappers, 0, false);
+ tracer.endSubscribeRpcSpan(subscribeAckRpcSpan);
+ tracer.addEndRpcEvent(subscribeMessageWrapper, true, false, 0);
+ Span subscribeNackRpcSpan =
+ tracer.startSubscribeRpcSpan(
+ FULL_SUBSCRIPTION_NAME, "nack", subscribeMessageWrappers, 0, false);
+ tracer.endSubscribeRpcSpan(subscribeNackRpcSpan);
+ tracer.addEndRpcEvent(subscribeMessageWrapper, true, true, 0);
+ tracer.endSubscriberSpan(subscribeMessageWrapper);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(8, allSpans.size());
+
+ SpanData publisherSpanData = allSpans.get(0);
+ SpanData concurrencyControlSpanData = allSpans.get(1);
+ SpanData schedulerSpanData = allSpans.get(2);
+ SpanData processSpanData = allSpans.get(3);
+ SpanData modackRpcSpanData = allSpans.get(4);
+ SpanData ackRpcSpanData = allSpans.get(5);
+ SpanData nackRpcSpanData = allSpans.get(6);
+ SpanData subscriberSpanData = allSpans.get(7);
+
+ SpanDataAssert concurrencyControlSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(concurrencyControlSpanData);
+ concurrencyControlSpanDataAssert
+ .hasName(SUBSCRIBE_CONCURRENCY_CONTROL_SPAN_NAME)
+ .hasParent(subscriberSpanData)
+ .hasEnded();
+
+ SpanDataAssert schedulerSpanDataAssert = OpenTelemetryAssertions.assertThat(schedulerSpanData);
+ schedulerSpanDataAssert
+ .hasName(SUBSCRIBE_SCHEDULER_SPAN_NAME)
+ .hasParent(subscriberSpanData)
+ .hasEnded();
+
+ SpanDataAssert processSpanDataAssert = OpenTelemetryAssertions.assertThat(processSpanData);
+ processSpanDataAssert
+ .hasName(SUBSCRIBE_PROCESS_SPAN_NAME)
+ .hasParent(subscriberSpanData)
+ .hasEnded();
+
+ assertEquals(1, processSpanData.getEvents().size());
+ EventDataAssert actionCalledEventAssert =
+ OpenTelemetryAssertions.assertThat(processSpanData.getEvents().get(0));
+ actionCalledEventAssert.hasName(PROCESS_ACTION + " called");
+
+ // Check span data, links, and attributes for the modack RPC span
+ SpanDataAssert modackRpcSpanDataAssert = OpenTelemetryAssertions.assertThat(modackRpcSpanData);
+ modackRpcSpanDataAssert
+ .hasName(SUBSCRIBE_MODACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasEnded();
+
+ List modackRpcLinks = modackRpcSpanData.getLinks();
+ assertEquals(subscribeMessageWrappers.size(), modackRpcLinks.size());
+ assertEquals(subscriberSpanData.getSpanContext(), modackRpcLinks.get(0).getSpanContext());
+
+ assertEquals(8, modackRpcSpanData.getAttributes().size());
+ AttributesAssert modackRpcSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(modackRpcSpanData.getAttributes());
+ modackRpcSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(
+ MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_SUBSCRIPTION_NAME.getSubscription())
+ .containsEntry(PROJECT_ATTR_KEY, FULL_TOPIC_NAME.getProject())
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "sendModAckOperations")
+ .containsEntry(MESSAGING_OPERATION_ATTR_KEY, "modack")
+ .containsEntry(MESSAGING_BATCH_MESSAGE_COUNT_ATTR_KEY, subscribeMessageWrappers.size())
+ .containsEntry(ACK_DEADLINE_ATTR_KEY, 10)
+ .containsEntry(RECEIPT_MODACK_ATTR_KEY, true);
+
+ // Check span data, links, and attributes for the ack RPC span
+ SpanDataAssert ackRpcSpanDataAssert = OpenTelemetryAssertions.assertThat(ackRpcSpanData);
+ ackRpcSpanDataAssert
+ .hasName(SUBSCRIBE_ACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasEnded();
+
+ List ackRpcLinks = ackRpcSpanData.getLinks();
+ assertEquals(subscribeMessageWrappers.size(), ackRpcLinks.size());
+ assertEquals(subscriberSpanData.getSpanContext(), ackRpcLinks.get(0).getSpanContext());
+
+ assertEquals(6, ackRpcSpanData.getAttributes().size());
+ AttributesAssert ackRpcSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(ackRpcSpanData.getAttributes());
+ ackRpcSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(
+ MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_SUBSCRIPTION_NAME.getSubscription())
+ .containsEntry(PROJECT_ATTR_KEY, FULL_TOPIC_NAME.getProject())
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "sendAckOperations")
+ .containsEntry(MESSAGING_OPERATION_ATTR_KEY, "ack")
+ .containsEntry(MESSAGING_BATCH_MESSAGE_COUNT_ATTR_KEY, subscribeMessageWrappers.size());
+
+ // Check span data, links, and attributes for the nack RPC span
+ SpanDataAssert nackRpcSpanDataAssert = OpenTelemetryAssertions.assertThat(nackRpcSpanData);
+ nackRpcSpanDataAssert
+ .hasName(SUBSCRIBE_NACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasEnded();
+
+ List nackRpcLinks = nackRpcSpanData.getLinks();
+ assertEquals(subscribeMessageWrappers.size(), nackRpcLinks.size());
+ assertEquals(subscriberSpanData.getSpanContext(), nackRpcLinks.get(0).getSpanContext());
+
+ assertEquals(6, nackRpcSpanData.getAttributes().size());
+ AttributesAssert nackRpcSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(nackRpcSpanData.getAttributes());
+ nackRpcSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(
+ MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_SUBSCRIPTION_NAME.getSubscription())
+ .containsEntry(PROJECT_ATTR_KEY, FULL_TOPIC_NAME.getProject())
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "sendModAckOperations")
+ .containsEntry(MESSAGING_OPERATION_ATTR_KEY, "nack")
+ .containsEntry(MESSAGING_BATCH_MESSAGE_COUNT_ATTR_KEY, subscribeMessageWrappers.size());
+
+ // Check span data, events, links, and attributes for the publisher create span
+ SpanDataAssert subscriberSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData);
+ subscriberSpanDataAssert
+ .hasName(SUBSCRIBER_SPAN_NAME)
+ .hasKind(SpanKind.CONSUMER)
+ .hasParent(publisherSpanData)
+ .hasEnded();
+
+ assertEquals(6, subscriberSpanData.getEvents().size());
+ EventDataAssert startModackEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(0));
+ startModackEventAssert.hasName(MODACK_START_EVENT);
+ EventDataAssert endModackEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(1));
+ endModackEventAssert.hasName(MODACK_END_EVENT);
+ EventDataAssert startAckEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(2));
+ startAckEventAssert.hasName(ACK_START_EVENT);
+ EventDataAssert endAckEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(3));
+ endAckEventAssert.hasName(ACK_END_EVENT);
+ EventDataAssert startNackEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(4));
+ startNackEventAssert.hasName(NACK_START_EVENT);
+ EventDataAssert endNackEventAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getEvents().get(5));
+ endNackEventAssert.hasName(NACK_END_EVENT);
+
+ List subscriberLinks = subscriberSpanData.getLinks();
+ assertEquals(3, subscriberLinks.size());
+ assertEquals(modackRpcSpanData.getSpanContext(), subscriberLinks.get(0).getSpanContext());
+ assertEquals(ackRpcSpanData.getSpanContext(), subscriberLinks.get(1).getSpanContext());
+ assertEquals(nackRpcSpanData.getSpanContext(), subscriberLinks.get(2).getSpanContext());
+
+ assertEquals(11, subscriberSpanData.getAttributes().size());
+ AttributesAssert subscriberSpanAttributesAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData.getAttributes());
+ subscriberSpanAttributesAssert
+ .containsEntry(MESSAGING_SYSTEM_ATTR_KEY, MESSAGING_SYSTEM_VALUE)
+ .containsEntry(
+ MESSAGING_DESTINATION_NAME_ATTR_KEY, FULL_SUBSCRIPTION_NAME.getSubscription())
+ .containsEntry(PROJECT_ATTR_KEY, PROJECT_NAME)
+ .containsEntry(CODE_FUNCTION_ATTR_KEY, "onResponse")
+ .containsEntry(MESSAGE_SIZE_ATTR_KEY, messageSize)
+ .containsEntry(ORDERING_KEY_ATTR_KEY, ORDERING_KEY)
+ .containsEntry(MESSAGE_ACK_ID_ATTR_KEY, ACK_ID)
+ .containsEntry(MESSAGE_DELIVERY_ATTEMPT_ATTR_KEY, DELIVERY_ATTEMPT)
+ .containsEntry(MESSAGE_EXACTLY_ONCE_ATTR_KEY, EXACTLY_ONCE_ENABLED)
+ .containsEntry(MESSAGE_RESULT_ATTR_KEY, PROCESS_ACTION)
+ .containsEntry(MESSAGING_MESSAGE_ID_ATTR_KEY, MESSAGE_ID);
+ }
+
+ @Test
+ public void testSubscribeConcurrencyControlSpanFailure() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(
+ getPubsubMessage(), FULL_SUBSCRIPTION_NAME, ACK_ID, DELIVERY_ATTEMPT)
+ .build();
+
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ tracer.startSubscriberSpan(messageWrapper, EXACTLY_ONCE_ENABLED);
+ tracer.startSubscribeConcurrencyControlSpan(messageWrapper);
+
+ Exception e = new Exception("test-exception");
+ tracer.setSubscribeConcurrencyControlSpanException(messageWrapper, e);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(2, allSpans.size());
+ SpanData concurrencyControlSpanData = allSpans.get(0);
+ SpanData subscriberSpanData = allSpans.get(1);
+
+ SpanDataAssert concurrencyControlSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(concurrencyControlSpanData);
+ StatusData expectedStatus =
+ StatusData.create(
+ StatusCode.ERROR, "Exception thrown during subscribe concurrency control.");
+ concurrencyControlSpanDataAssert
+ .hasName(SUBSCRIBE_CONCURRENCY_CONTROL_SPAN_NAME)
+ .hasParent(subscriberSpanData)
+ .hasStatus(expectedStatus)
+ .hasException(e)
+ .hasEnded();
+
+ SpanDataAssert subscriberSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData);
+ subscriberSpanDataAssert
+ .hasName(SUBSCRIBER_SPAN_NAME)
+ .hasKind(SpanKind.CONSUMER)
+ .hasNoParent()
+ .hasEnded();
+ }
+
+ @Test
+ public void testSubscriberSpanFailure() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(
+ getPubsubMessage(), FULL_SUBSCRIPTION_NAME, ACK_ID, DELIVERY_ATTEMPT)
+ .build();
+
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ tracer.startSubscriberSpan(messageWrapper, EXACTLY_ONCE_ENABLED);
+
+ Exception e = new Exception("test-exception");
+ tracer.setSubscriberSpanException(messageWrapper, e, "Test exception");
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(1, allSpans.size());
+ SpanData subscriberSpanData = allSpans.get(0);
+
+ StatusData expectedStatus = StatusData.create(StatusCode.ERROR, "Test exception");
+ SpanDataAssert subscriberSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(subscriberSpanData);
+ subscriberSpanDataAssert
+ .hasName(SUBSCRIBER_SPAN_NAME)
+ .hasKind(SpanKind.CONSUMER)
+ .hasNoParent()
+ .hasStatus(expectedStatus)
+ .hasException(e)
+ .hasEnded();
+ }
+
+ @Test
+ public void testSubscribeRpcSpanFailures() {
+ openTelemetryTesting.clearSpans();
+
+ PubsubMessageWrapper messageWrapper =
+ PubsubMessageWrapper.newBuilder(
+ getPubsubMessage(), FULL_SUBSCRIPTION_NAME, ACK_ID, DELIVERY_ATTEMPT)
+ .build();
+ List messageWrappers = Arrays.asList(messageWrapper);
+
+ Tracer openTelemetryTracer = openTelemetryTesting.getOpenTelemetry().getTracer("test");
+ OpenTelemetryPubsubTracer tracer = new OpenTelemetryPubsubTracer(openTelemetryTracer, true);
+
+ tracer.startSubscriberSpan(messageWrapper, EXACTLY_ONCE_ENABLED);
+ Span subscribeModackRpcSpan =
+ tracer.startSubscribeRpcSpan(
+ FULL_SUBSCRIPTION_NAME, "modack", messageWrappers, ACK_DEADLINE, true);
+ Span subscribeAckRpcSpan =
+ tracer.startSubscribeRpcSpan(FULL_SUBSCRIPTION_NAME, "ack", messageWrappers, 0, false);
+ Span subscribeNackRpcSpan =
+ tracer.startSubscribeRpcSpan(FULL_SUBSCRIPTION_NAME, "nack", messageWrappers, 0, false);
+
+ Exception e = new Exception("test-exception");
+ tracer.setSubscribeRpcSpanException(subscribeModackRpcSpan, true, ACK_DEADLINE, e);
+ tracer.setSubscribeRpcSpanException(subscribeAckRpcSpan, false, 0, e);
+ tracer.setSubscribeRpcSpanException(subscribeNackRpcSpan, true, 0, e);
+ tracer.endSubscriberSpan(messageWrapper);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(4, allSpans.size());
+ SpanData modackSpanData = allSpans.get(0);
+ SpanData ackSpanData = allSpans.get(1);
+ SpanData nackSpanData = allSpans.get(2);
+ SpanData subscriberSpanData = allSpans.get(3);
+
+ StatusData expectedModackStatus =
+ StatusData.create(StatusCode.ERROR, "Exception thrown on modack RPC.");
+ SpanDataAssert modackSpanDataAssert = OpenTelemetryAssertions.assertThat(modackSpanData);
+ modackSpanDataAssert
+ .hasName(SUBSCRIBE_MODACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasStatus(expectedModackStatus)
+ .hasException(e)
+ .hasEnded();
+
+ StatusData expectedAckStatus =
+ StatusData.create(StatusCode.ERROR, "Exception thrown on ack RPC.");
+ SpanDataAssert ackSpanDataAssert = OpenTelemetryAssertions.assertThat(ackSpanData);
+ ackSpanDataAssert
+ .hasName(SUBSCRIBE_ACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasStatus(expectedAckStatus)
+ .hasException(e)
+ .hasEnded();
+
+ StatusData expectedNackStatus =
+ StatusData.create(StatusCode.ERROR, "Exception thrown on nack RPC.");
+ SpanDataAssert nackSpanDataAssert = OpenTelemetryAssertions.assertThat(nackSpanData);
+ nackSpanDataAssert
+ .hasName(SUBSCRIBE_NACK_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasStatus(expectedNackStatus)
+ .hasException(e)
+ .hasEnded();
+ }
+
+ private PubsubMessage getPubsubMessage() {
+ return PubsubMessage.newBuilder()
+ .setData(ByteString.copyFromUtf8("test-data"))
+ .setOrderingKey(ORDERING_KEY)
+ .build();
+ }
+}
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/PublisherImplTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/PublisherImplTest.java
index 9785b7716..39155c848 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/PublisherImplTest.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/PublisherImplTest.java
@@ -48,6 +48,13 @@
import io.grpc.StatusException;
import io.grpc.inprocess.InProcessChannelBuilder;
import io.grpc.inprocess.InProcessServerBuilder;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
+import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
+import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
+import io.opentelemetry.sdk.trace.data.SpanData;
+import java.time.Duration;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -60,7 +67,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.threeten.bp.Duration;
@RunWith(JUnit4.class)
public class PublisherImplTest {
@@ -74,6 +80,11 @@ public class PublisherImplTest {
private static final TransportChannelProvider TEST_CHANNEL_PROVIDER =
LocalChannelProvider.create("test-server");
+ private static final String PUBLISHER_SPAN_NAME = TEST_TOPIC.getTopic() + " create";
+ private static final String PUBLISH_FLOW_CONTROL_SPAN_NAME = "publisher flow control";
+ private static final String PUBLISH_BATCHING_SPAN_NAME = "publisher batching";
+ private static final String PUBLISH_RPC_SPAN_NAME = TEST_TOPIC.getTopic() + " publish";
+
private FakeScheduledExecutorService fakeExecutor;
private FakePublisherServiceImpl testPublisherServiceImpl;
@@ -107,9 +118,8 @@ public void testPublishByDuration() throws Exception {
getTestPublisherBuilder()
// To demonstrate that reaching duration will trigger publish
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
- .setDelayThreshold(Duration.ofSeconds(5))
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setElementCountThreshold(10L)
.build())
.build();
@@ -137,10 +147,9 @@ public void testPublishByNumBatchedMessages() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(2L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.build();
@@ -176,10 +185,9 @@ public void testSinglePublishByNumBytes() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(2L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.build();
@@ -212,9 +220,8 @@ public void testPublishByShutdown() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
- .setDelayThreshold(Duration.ofSeconds(100))
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.setElementCountThreshold(10L)
.build())
.build();
@@ -245,10 +252,9 @@ public void testPublishMixedSizeAndDuration() throws Exception {
getTestPublisherBuilder()
// To demonstrate that reaching duration will trigger publish
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(2L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.build())
.build();
@@ -286,10 +292,9 @@ public void testPublishWithCompression() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(2L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.setEnableCompression(true)
.setCompressionBytesThreshold(100)
@@ -317,10 +322,9 @@ public void testBatchedMessagesWithOrderingKeyByNum() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(3L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.setEnableMessageOrdering(true)
.build();
@@ -370,10 +374,9 @@ public void testBatchedMessagesWithOrderingKeyByDuration() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(10L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.setEnableMessageOrdering(true)
.build();
@@ -433,11 +436,10 @@ public void testLargeMessagesDoNotReorderBatches() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(10L)
- .setRequestByteThreshold(20L)
- .setDelayThreshold(Duration.ofSeconds(100))
+ .setRequestByteThreshold(64L)
+ .setDelayThresholdDuration(Duration.ofSeconds(100))
.build())
.setEnableMessageOrdering(true)
.build();
@@ -477,9 +479,8 @@ public void testEnableMessageOrdering_overwritesMaxAttempts() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.setMaxAttempts(1)
.build())
.setEnableMessageOrdering(true)
@@ -602,7 +603,7 @@ public void testPublishThrowExceptionForUnsubmittedOrderingKeyMessage() throws E
Publisher.Builder.DEFAULT_BATCHING_SETTINGS
.toBuilder()
.setElementCountThreshold(2L)
- .setDelayThreshold(Duration.ofSeconds(500))
+ .setDelayThresholdDuration(Duration.ofSeconds(500))
.build())
.setEnableMessageOrdering(true)
.build();
@@ -660,10 +661,9 @@ public void testErrorPropagation() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.build())
.build();
testPublisherServiceImpl.addPublishError(Status.DATA_LOSS.asException());
@@ -681,10 +681,9 @@ public void testPublishFailureRetries() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.build())
.build(); // To demonstrate that reaching duration will trigger publish
@@ -705,9 +704,8 @@ public void testPublishFailureRetries_retriesDisabled() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.setMaxAttempts(1)
.build())
.build();
@@ -730,9 +728,8 @@ public void testPublishFailureRetries_maxRetriesSetup() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.setMaxAttempts(3)
.build())
.build();
@@ -755,9 +752,8 @@ public void testPublishFailureRetries_maxRetriesSetUnlimited() throws Exception
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.setMaxAttempts(0)
.build())
.build();
@@ -781,15 +777,13 @@ public void testPublishFailureRetries_nonRetryableFailsImmediately() throws Exce
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.build())
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.build())
.build(); // To demonstrate that reaching duration will trigger publish
@@ -814,7 +808,7 @@ public void testPublisherGetters() throws Exception {
builder.setBatchingSettings(
BatchingSettings.newBuilder()
.setRequestByteThreshold(10L)
- .setDelayThreshold(Duration.ofMillis(11))
+ .setDelayThresholdDuration(Duration.ofMillis(11))
.setElementCountThreshold(12L)
.build());
builder.setCredentialsProvider(NoCredentialsProvider.create());
@@ -822,7 +816,8 @@ public void testPublisherGetters() throws Exception {
assertEquals(TEST_TOPIC, publisher.getTopicName());
assertEquals(10, (long) publisher.getBatchingSettings().getRequestByteThreshold());
- assertEquals(Duration.ofMillis(11), publisher.getBatchingSettings().getDelayThreshold());
+ assertEquals(
+ Duration.ofMillis(11), publisher.getBatchingSettings().getDelayThresholdDuration());
assertEquals(12, (long) publisher.getBatchingSettings().getElementCountThreshold());
publisher.shutdown();
assertTrue(publisher.awaitTermination(1, TimeUnit.MINUTES));
@@ -837,7 +832,8 @@ public void testBuilderParametersAndDefaults() {
Publisher.Builder.DEFAULT_REQUEST_BYTES_THRESHOLD,
builder.batchingSettings.getRequestByteThreshold().longValue());
assertEquals(
- Publisher.Builder.DEFAULT_DELAY_THRESHOLD, builder.batchingSettings.getDelayThreshold());
+ Publisher.Builder.DEFAULT_DELAY_THRESHOLD,
+ builder.batchingSettings.getDelayThresholdDuration());
assertEquals(
Publisher.Builder.DEFAULT_ELEMENT_COUNT_THRESHOLD,
builder.batchingSettings.getElementCountThreshold().longValue());
@@ -863,8 +859,7 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setRequestByteThreshold(null)
.build());
fail("Should have thrown an NullPointerException");
@@ -873,8 +868,7 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setRequestByteThreshold(0L)
.build());
fail("Should have thrown an IllegalArgumentException");
@@ -883,8 +877,7 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setRequestByteThreshold(-1L)
.build());
fail("Should have thrown an IllegalArgumentException");
@@ -893,9 +886,8 @@ public void testBuilderInvalidArguments() {
}
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
- .setDelayThreshold(Duration.ofMillis(1))
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
+ .setDelayThresholdDuration(Duration.ofMillis(1))
.build());
try {
builder.setBatchingSettings(
@@ -906,9 +898,8 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
- .setDelayThreshold(Duration.ofMillis(-1))
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
+ .setDelayThresholdDuration(Duration.ofMillis(-1))
.build());
fail("Should have thrown an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
@@ -916,14 +907,12 @@ public void testBuilderInvalidArguments() {
}
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
.build());
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(null)
.build());
fail("Should have thrown an NullPointerException");
@@ -932,8 +921,7 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(0L)
.build());
fail("Should have thrown an IllegalArgumentException");
@@ -942,8 +930,7 @@ public void testBuilderInvalidArguments() {
}
try {
builder.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(-1L)
.build());
fail("Should have thrown an IllegalArgumentException");
@@ -952,30 +939,26 @@ public void testBuilderInvalidArguments() {
}
builder.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setInitialRpcTimeout(Publisher.Builder.MIN_RPC_TIMEOUT)
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setInitialRpcTimeoutDuration(Publisher.Builder.MIN_RPC_TIMEOUT)
.build());
try {
builder.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setInitialRpcTimeout(Publisher.Builder.MIN_RPC_TIMEOUT.minusMillis(1))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setInitialRpcTimeoutDuration(Publisher.Builder.MIN_RPC_TIMEOUT.minusMillis(1))
.build());
fail("Should have thrown an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
// Expected
}
builder.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Publisher.Builder.MIN_TOTAL_TIMEOUT)
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Publisher.Builder.MIN_TOTAL_TIMEOUT)
.build());
try {
builder.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Publisher.Builder.MIN_TOTAL_TIMEOUT.minusMillis(1))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Publisher.Builder.MIN_TOTAL_TIMEOUT.minusMillis(1))
.build());
fail("Should have thrown an IllegalArgumentException");
} catch (IllegalArgumentException expected) {
@@ -988,8 +971,7 @@ public void testPartialBatchingSettings() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.getDefaultBatchingSettings()
- .toBuilder()
+ Publisher.Builder.getDefaultBatchingSettings().toBuilder()
.setRequestByteThreshold(5000L)
.build())
.build();
@@ -1001,8 +983,7 @@ public void testPartialBatchingSettings() throws Exception {
publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.getDefaultBatchingSettings()
- .toBuilder()
+ Publisher.Builder.getDefaultBatchingSettings().toBuilder()
.setElementCountThreshold(500L)
.build())
.build();
@@ -1018,9 +999,8 @@ public void testAwaitTermination() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setRetrySettings(
- Publisher.Builder.DEFAULT_RETRY_SETTINGS
- .toBuilder()
- .setTotalTimeout(Duration.ofSeconds(10))
+ Publisher.Builder.DEFAULT_RETRY_SETTINGS.toBuilder()
+ .setTotalTimeoutDuration(Duration.ofSeconds(10))
.setMaxAttempts(0)
.build())
.build();
@@ -1052,10 +1032,9 @@ public void invalidFlowControlBytes_throwException() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(
@@ -1077,10 +1056,9 @@ public void invalidFlowControlElementCount_throwException() throws Exception {
Publisher publisher =
getTestPublisherBuilder()
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(
@@ -1102,10 +1080,9 @@ public void testMessageExceedsFlowControlLimits_throwException() throws Exceptio
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(FlowController.LimitExceededBehavior.Block)
@@ -1130,16 +1107,15 @@ public void testPublishFlowControl_throwException() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(
FlowController.LimitExceededBehavior.ThrowException)
.setMaxOutstandingElementCount(1L)
- .setMaxOutstandingRequestBytes(10L)
+ .setMaxOutstandingRequestBytes(13L)
.build())
.build())
.build();
@@ -1172,16 +1148,15 @@ public void testPublishFlowControl_throwExceptionWithOrderingKey() throws Except
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(
FlowController.LimitExceededBehavior.ThrowException)
.setMaxOutstandingElementCount(1L)
- .setMaxOutstandingRequestBytes(10L)
+ .setMaxOutstandingRequestBytes(13L)
.build())
.build())
.setEnableMessageOrdering(true)
@@ -1219,15 +1194,14 @@ public void testPublishFlowControl_block() throws Exception {
getTestPublisherBuilder()
.setExecutorProvider(SINGLE_THREAD_EXECUTOR)
.setBatchingSettings(
- Publisher.Builder.DEFAULT_BATCHING_SETTINGS
- .toBuilder()
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
.setElementCountThreshold(1L)
- .setDelayThreshold(Duration.ofSeconds(5))
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
.setFlowControlSettings(
FlowControlSettings.newBuilder()
.setLimitExceededBehavior(FlowController.LimitExceededBehavior.Block)
.setMaxOutstandingElementCount(2L)
- .setMaxOutstandingRequestBytes(10L)
+ .setMaxOutstandingRequestBytes(13L)
.build())
.build())
.build();
@@ -1304,6 +1278,70 @@ public void run() {
publish4Completed.await();
}
+ @Test
+ public void testPublishOpenTelemetryTracing() throws Exception {
+ OpenTelemetryRule openTelemetryTesting = OpenTelemetryRule.create();
+ OpenTelemetry openTelemetry = openTelemetryTesting.getOpenTelemetry();
+ final Publisher publisher =
+ getTestPublisherBuilder()
+ .setBatchingSettings(
+ Publisher.Builder.DEFAULT_BATCHING_SETTINGS.toBuilder()
+ .setElementCountThreshold(1L)
+ .setDelayThresholdDuration(Duration.ofSeconds(5))
+ .setFlowControlSettings(
+ FlowControlSettings.newBuilder()
+ .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Block)
+ .setMaxOutstandingElementCount(2L)
+ .setMaxOutstandingRequestBytes(100L)
+ .build())
+ .build())
+ .setOpenTelemetry(openTelemetry)
+ .setEnableOpenTelemetryTracing(true)
+ .build();
+
+ testPublisherServiceImpl.addPublishResponse(PublishResponse.newBuilder().addMessageIds("1"));
+ ApiFuture publishFuture = sendTestMessage(publisher, "A");
+ fakeExecutor.advanceTime(Duration.ofSeconds(5));
+ assertEquals("1", publishFuture.get());
+ fakeExecutor.advanceTime(Duration.ofSeconds(5));
+ shutdownTestPublisher(publisher);
+
+ List allSpans = openTelemetryTesting.getSpans();
+ assertEquals(4, allSpans.size());
+ SpanData flowControlSpanData = allSpans.get(0);
+ SpanData batchingSpanData = allSpans.get(1);
+ SpanData publishRpcSpanData = allSpans.get(2);
+ SpanData publisherSpanData = allSpans.get(3);
+
+ SpanDataAssert flowControlSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(flowControlSpanData);
+ flowControlSpanDataAssert
+ .hasName(PUBLISH_FLOW_CONTROL_SPAN_NAME)
+ .hasParent(publisherSpanData)
+ .hasEnded();
+
+ SpanDataAssert batchingSpanDataAssert = OpenTelemetryAssertions.assertThat(batchingSpanData);
+ batchingSpanDataAssert
+ .hasName(PUBLISH_BATCHING_SPAN_NAME)
+ .hasParent(publisherSpanData)
+ .hasEnded();
+
+ SpanDataAssert publishRpcSpanDataAssert =
+ OpenTelemetryAssertions.assertThat(publishRpcSpanData);
+ publishRpcSpanDataAssert
+ .hasName(PUBLISH_RPC_SPAN_NAME)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasEnded();
+
+ SpanDataAssert publishSpanDataAssert = OpenTelemetryAssertions.assertThat(publisherSpanData);
+ publishSpanDataAssert
+ .hasName(PUBLISHER_SPAN_NAME)
+ .hasKind(SpanKind.PRODUCER)
+ .hasNoParent()
+ .hasEnded();
+ }
+
private Builder getTestPublisherBuilder() {
return Publisher.newBuilder(TEST_TOPIC)
.setExecutorProvider(FixedExecutorProvider.create(fakeExecutor))
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientHttpJsonTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientHttpJsonTest.java
index 964b25a6e..a8fcaedc6 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientHttpJsonTest.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientHttpJsonTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientTest.java
index 7d216444b..7e354bf49 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientTest.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/SchemaServiceClientTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * 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.
diff --git a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/StreamingSubscriberConnectionTest.java b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/StreamingSubscriberConnectionTest.java
index 95f8897a4..6979963a5 100644
--- a/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/StreamingSubscriberConnectionTest.java
+++ b/google-cloud-pubsub/src/test/java/com/google/cloud/pubsub/v1/StreamingSubscriberConnectionTest.java
@@ -17,6 +17,8 @@
package com.google.cloud.pubsub.v1;
import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.*;
import com.google.api.core.ApiFutures;
@@ -24,24 +26,37 @@
import com.google.api.gax.batching.FlowControlSettings;
import com.google.api.gax.batching.FlowController;
import com.google.api.gax.core.Distribution;
+import com.google.api.gax.grpc.GrpcStatusCode;
+import com.google.api.gax.rpc.ApiException;
+import com.google.api.gax.rpc.BidiStreamingCallable;
+import com.google.api.gax.rpc.ClientStream;
+import com.google.api.gax.rpc.ResponseObserver;
import com.google.api.gax.rpc.StatusCode;
+import com.google.api.gax.rpc.StreamController;
import com.google.cloud.pubsub.v1.stub.SubscriberStub;
import com.google.common.collect.Lists;
import com.google.protobuf.Any;
import com.google.pubsub.v1.AcknowledgeRequest;
import com.google.pubsub.v1.ModifyAckDeadlineRequest;
+import com.google.pubsub.v1.StreamingPullRequest;
+import com.google.pubsub.v1.StreamingPullResponse;
import com.google.rpc.ErrorInfo;
import com.google.rpc.Status;
+import io.grpc.Status.Code;
import io.grpc.StatusException;
import io.grpc.protobuf.StatusProto;
+import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
-import org.threeten.bp.Duration;
+import org.mockito.ArgumentCaptor;
/** Tests for {@link StreamingSubscriberConnection}. */
public class StreamingSubscriberConnectionTest {
@@ -52,7 +67,8 @@ public class StreamingSubscriberConnectionTest {
private FakeClock clock;
private SubscriberStub mockSubscriberStub;
- private static final String MOCK_SUBSCRIPTION_NAME = "MOCK-SUBSCRIPTION";
+ private static final String MOCK_SUBSCRIPTION_NAME =
+ "projects/MOCK-PROJECT/subscriptions/MOCK-SUBSCRIPTION";
private static final String MOCK_ACK_ID_SUCCESS = "MOCK-ACK-ID-SUCCESS";
private static final String MOCK_ACK_ID_SUCCESS_2 = "MOCK-ACK-ID-SUCCESS-2";
private static final String MOCK_ACK_ID_NACK_SUCCESS = "MOCK-ACK-ID-NACK-SUCCESS";
@@ -64,6 +80,8 @@ public class StreamingSubscriberConnectionTest {
"MOCK-ACK-ID-TRANSIENT-FAILURE-SERVICE-UNAVAILABLE-THEN-SUCCESS";
private static final String MOCK_ACK_ID_INVALID = "MOCK-ACK-ID-INVALID";
private static final String MOCK_ACK_ID_OTHER = "MOCK-ACK-ID-OTHER";
+ private static final String MOCK_ACK_ID_NO_METADATA_MAP_INTERNAL_ERROR_THEN_PERMISSION_DENIED =
+ "MOCK-ACK-ID-NO-METADATA-MAP-INTERNAL-ERROR";
private static final String PERMANENT_FAILURE_INVALID_ACK_ID = "PERMANENT_FAILURE_INVALID_ACK_ID";
private static final String TRANSIENT_FAILURE_UNORDERED_ACK_ID =
@@ -76,6 +94,10 @@ public class StreamingSubscriberConnectionTest {
private static Duration ACK_EXPIRATION_PADDING_DEFAULT_DURATION = Duration.ofSeconds(10);
private static int MAX_DURATION_PER_ACK_EXTENSION_DEFAULT_SECONDS = 10;
+ private static final long KEEP_ALIVE_SUPPORT_VERSION = 1;
+ private static final Duration CLIENT_PING_INTERVAL = Duration.ofSeconds(30);
+ private static final Duration MAX_ACK_EXTENSION_PERIOD = Duration.ofMinutes(60);
+
@Before
public void setUp() {
systemExecutor = new FakeScheduledExecutorService();
@@ -99,6 +121,110 @@ public void testSetupAndTeardown() {
streamingSubscriberConnection.awaitTerminated();
}
+ @Test
+ public void testRunShutdown_TimeoutMet() throws Exception {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder().setTimeout(Duration.ofSeconds(10)).build();
+ StreamingSubscriberConnection.Builder builder =
+ StreamingSubscriberConnection.newBuilder(mock(MessageReceiverWithAckResponse.class));
+ builder.setSubscriberShutdownSettings(shutdownSettings);
+ StreamingSubscriberConnection streamingSubscriberConnection =
+ getStreamingSubscriberConnectionFromBuilder(builder);
+
+ streamingSubscriberConnection.startAsync().awaitRunning();
+ streamingSubscriberConnection.stopAsync();
+
+ // Should terminate quickly as there are no outstanding messages.
+ streamingSubscriberConnection.awaitTerminated(1, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void testRunShutdown_TimeoutExceeded() throws Exception {
+ final SettableApiFuture ackFuture = SettableApiFuture.create();
+ when(mockSubscriberStub.acknowledgeCallable().futureCall(any(AcknowledgeRequest.class)))
+ .thenReturn(ackFuture);
+
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder().setTimeout(Duration.ofSeconds(2)).build();
+ StreamingSubscriberConnection.Builder builder =
+ StreamingSubscriberConnection.newBuilder(mock(MessageReceiverWithAckResponse.class));
+ StreamingSubscriberConnection streamingSubscriberConnection =
+ getStreamingSubscriberConnectionFromBuilder(builder, shutdownSettings);
+ streamingSubscriberConnection.setExactlyOnceDeliveryEnabled(true);
+
+ streamingSubscriberConnection.startAsync().awaitRunning();
+
+ // Send an ACK that will not complete.
+ SettableApiFuture messageFuture = SettableApiFuture.create();
+ streamingSubscriberConnection.sendAckOperations(
+ Collections.singletonList(
+ AckRequestData.newBuilder("ack1").setMessageFuture(messageFuture).build()));
+
+ Thread t =
+ new Thread(
+ () -> {
+ streamingSubscriberConnection.stopAsync();
+ });
+ t.start();
+
+ Thread t2 =
+ new Thread(
+ () -> {
+ try {
+ streamingSubscriberConnection.awaitTerminated(1, TimeUnit.SECONDS);
+ fail("Should have timed out");
+ } catch (TimeoutException e) {
+ // expected
+ }
+ });
+ t2.start();
+ t2.join();
+
+ // Advance the clock past the shutdown timeout.
+ clock.advance(3, TimeUnit.SECONDS);
+ t.join();
+
+ // Now it should terminate.
+ streamingSubscriberConnection.awaitTerminated();
+ assertFalse(streamingSubscriberConnection.isRunning());
+ assertFalse(messageFuture.isDone());
+ }
+
+ @Test
+ public void testAckDuringNackImmediatelyShutdown() throws Exception {
+ SubscriberShutdownSettings shutdownSettings =
+ SubscriberShutdownSettings.newBuilder()
+ .setMode(SubscriberShutdownSettings.ShutdownMode.NACK_IMMEDIATELY)
+ .build();
+
+ MessageDispatcher mockMessageDispatcher = mock(MessageDispatcher.class);
+ when(mockMessageDispatcher.getNackImmediatelyShutdownInProgress()).thenReturn(true);
+
+ StreamingSubscriberConnection.Builder builder =
+ StreamingSubscriberConnection.newBuilder(mock(MessageReceiverWithAckResponse.class));
+ StreamingSubscriberConnection streamingSubscriberConnection =
+ getStreamingSubscriberConnectionFromBuilder(builder, shutdownSettings);
+
+ // Use reflection to set the mock message dispatcher
+ java.lang.reflect.Field dispatcherField =
+ StreamingSubscriberConnection.class.getDeclaredField("messageDispatcher");
+ dispatcherField.setAccessible(true);
+ dispatcherField.set(streamingSubscriberConnection, mockMessageDispatcher);
+
+ streamingSubscriberConnection.setExactlyOnceDeliveryEnabled(true);
+
+ SettableApiFuture messageFuture = SettableApiFuture.create();
+ AckRequestData ackRequestData =
+ AckRequestData.newBuilder("ack1").setMessageFuture(messageFuture).build();
+
+ when(mockSubscriberStub.acknowledgeCallable().futureCall(any()))
+ .thenReturn(ApiFutures.immediateFuture(null));
+ streamingSubscriberConnection.sendAckOperations(Collections.singletonList(ackRequestData));
+
+ verify(mockMessageDispatcher, times(1)).notifyAckFailed(ackRequestData);
+ assertEquals(AckResponse.OTHER, messageFuture.get());
+ }
+
@Test
public void testSendAckOperationsExactlyOnceDisabledNoMessageFutures() {
// Setup mocks
@@ -397,6 +523,62 @@ public void testSendAckOperationsExactlyOnceEnabledMessageFuturesAcks() {
}
}
+ @Test
+ public void testSendAckOperationsExactlyOnceEnabledErrorWithEmptyMetadataMap() {
+ // Setup
+
+ // The list(s) of ackIds allows us to mock the grpc response(s)
+ List ackIdsRequest = new ArrayList<>();
+ List ackRequestDataList = new ArrayList();
+
+ // Initial) INTERNAL error, retryable
+ // Retry) PERMISSION_DENIED, not retryable
+ SettableApiFuture messageInternalErrorThenPermissionDenied =
+ SettableApiFuture.create();
+ ackRequestDataList.add(
+ AckRequestData.newBuilder(MOCK_ACK_ID_NO_METADATA_MAP_INTERNAL_ERROR_THEN_PERMISSION_DENIED)
+ .setMessageFuture(messageInternalErrorThenPermissionDenied)
+ .build());
+ ackIdsRequest.add(MOCK_ACK_ID_NO_METADATA_MAP_INTERNAL_ERROR_THEN_PERMISSION_DENIED);
+
+ // Build our request so we can set our mock responses
+ AcknowledgeRequest acknowledgeRequest =
+ AcknowledgeRequest.newBuilder()
+ .setSubscription(MOCK_SUBSCRIPTION_NAME)
+ .addAllAckIds(ackIdsRequest)
+ .build();
+
+ ApiException internalError =
+ new ApiException("internal", null, GrpcStatusCode.of(Code.INTERNAL), true);
+ ApiException permissionDeniedError =
+ new ApiException(
+ "permission_denied", null, GrpcStatusCode.of(Code.PERMISSION_DENIED), false);
+ // Set mock grpc responses
+ when(mockSubscriberStub.acknowledgeCallable().futureCall(acknowledgeRequest))
+ .thenReturn(ApiFutures.immediateFailedFuture(internalError))
+ .thenReturn(ApiFutures.immediateFailedFuture(permissionDeniedError));
+
+ // Instantiate class and run operation(s)
+ StreamingSubscriberConnection streamingSubscriberConnection =
+ getStreamingSubscriberConnection(true);
+
+ streamingSubscriberConnection.sendAckOperations(ackRequestDataList);
+
+ // Backoff
+ systemExecutor.advanceTime(Duration.ofMillis(200));
+
+ // Assert expected behavior;
+ verify(mockSubscriberStub.acknowledgeCallable(), times(2)).futureCall(acknowledgeRequest);
+ verify(mockSubscriberStub, never()).modifyAckDeadlineCallable();
+
+ try {
+ assertEquals(AckResponse.PERMISSION_DENIED, messageInternalErrorThenPermissionDenied.get());
+ } catch (InterruptedException | ExecutionException e) {
+ // In case something goes wrong retrieving the futures
+ throw new AssertionError();
+ }
+ }
+
@Test
public void testSetFailureResponseOutstandingMessages() {
// Setup
@@ -500,6 +682,155 @@ public void testMaxPerRequestChanges() {
}
}
+ @Test
+ public void testClientPinger_pingSent() {
+ BidiStreamingCallable mockStreamingCallable =
+ mock(BidiStreamingCallable.class);
+ ClientStream