diff --git a/.changelog/5849.txt b/.changelog/5849.txt new file mode 100644 index 00000000000..0bcece3e072 --- /dev/null +++ b/.changelog/5849.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +pubsub: added `enable_exactly_once_delivery` to `google_pubsub_subscription` +``` diff --git a/google/resource_pubsub_subscription.go b/google/resource_pubsub_subscription.go index ed42d0a3ae4..9e096c4f09d 100644 --- a/google/resource_pubsub_subscription.go +++ b/google/resource_pubsub_subscription.go @@ -139,6 +139,20 @@ If this parameter is 0, a default value of 5 is used.`, }, }, }, + "enable_exactly_once_delivery": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: `If 'true', Pub/Sub provides the following guarantees for the delivery +of a message with a given value of messageId on this Subscriptions': + +- The message sent to a subscriber is guaranteed not to be resent before the message's acknowledgement deadline expires. + +- An acknowledged message will not be resent to a subscriber. + +Note that subscribers may still receive multiple copies of a message when 'enable_exactly_once_delivery' +is true if the message was published multiple times by a publisher client. These copies are considered distinct by Pub/Sub and have distinct messageId values`, + }, "enable_message_ordering": { Type: schema.TypeBool, Optional: true, @@ -194,7 +208,7 @@ you can't modify the filter.`, Optional: true, Description: `How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published. If -retainAckedMessages is true, then this also configures the retention +retain_acked_messages is true, then this also configures the retention of acknowledged messages, and thus configures how far back in time a subscriptions.seek can be done. Defaults to 7 days. Cannot be more than 7 days ('"604800s"') or less than 10 minutes ('"600s"'). @@ -408,6 +422,12 @@ func resourcePubsubSubscriptionCreate(d *schema.ResourceData, meta interface{}) } else if v, ok := d.GetOkExists("enable_message_ordering"); !isEmptyValue(reflect.ValueOf(enableMessageOrderingProp)) && (ok || !reflect.DeepEqual(v, enableMessageOrderingProp)) { obj["enableMessageOrdering"] = enableMessageOrderingProp } + enableExactlyOnceDeliveryProp, err := expandPubsubSubscriptionEnableExactlyOnceDelivery(d.Get("enable_exactly_once_delivery"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("enable_exactly_once_delivery"); !isEmptyValue(reflect.ValueOf(enableExactlyOnceDeliveryProp)) && (ok || !reflect.DeepEqual(v, enableExactlyOnceDeliveryProp)) { + obj["enableExactlyOnceDelivery"] = enableExactlyOnceDeliveryProp + } obj, err = resourcePubsubSubscriptionEncoder(d, meta, obj) if err != nil { @@ -560,6 +580,9 @@ func resourcePubsubSubscriptionRead(d *schema.ResourceData, meta interface{}) er if err := d.Set("enable_message_ordering", flattenPubsubSubscriptionEnableMessageOrdering(res["enableMessageOrdering"], d, config)); err != nil { return fmt.Errorf("Error reading Subscription: %s", err) } + if err := d.Set("enable_exactly_once_delivery", flattenPubsubSubscriptionEnableExactlyOnceDelivery(res["enableExactlyOnceDelivery"], d, config)); err != nil { + return fmt.Errorf("Error reading Subscription: %s", err) + } return nil } @@ -925,6 +948,10 @@ func flattenPubsubSubscriptionEnableMessageOrdering(v interface{}, d *schema.Res return v } +func flattenPubsubSubscriptionEnableExactlyOnceDelivery(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandPubsubSubscriptionName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return replaceVars(d, config, "projects/{{project}}/subscriptions/{{name}}") } @@ -1160,6 +1187,10 @@ func expandPubsubSubscriptionEnableMessageOrdering(v interface{}, d TerraformRes return v, nil } +func expandPubsubSubscriptionEnableExactlyOnceDelivery(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func resourcePubsubSubscriptionEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { delete(obj, "name") return obj, nil diff --git a/google/resource_pubsub_subscription_test.go b/google/resource_pubsub_subscription_test.go index 4d7e5baa55e..904c6827e12 100644 --- a/google/resource_pubsub_subscription_test.go +++ b/google/resource_pubsub_subscription_test.go @@ -44,7 +44,7 @@ func TestAccPubsubSubscription_basic(t *testing.T) { CheckDestroy: testAccCheckPubsubSubscriptionDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccPubsubSubscription_basic(topic, subscription, "bar", 20), + Config: testAccPubsubSubscription_basic(topic, subscription, "bar", 20, false), }, { ResourceName: "google_pubsub_subscription.foo", @@ -68,7 +68,7 @@ func TestAccPubsubSubscription_update(t *testing.T) { CheckDestroy: testAccCheckPubsubSubscriptionDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccPubsubSubscription_basic(topic, subscriptionShort, "bar", 20), + Config: testAccPubsubSubscription_basic(topic, subscriptionShort, "bar", 20, false), }, { ResourceName: "google_pubsub_subscription.foo", @@ -77,7 +77,7 @@ func TestAccPubsubSubscription_update(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccPubsubSubscription_basic(topic, subscriptionShort, "baz", 30), + Config: testAccPubsubSubscription_basic(topic, subscriptionShort, "baz", 30, true), }, { ResourceName: "google_pubsub_subscription.foo", @@ -209,7 +209,7 @@ resource "google_pubsub_subscription" "foo" { `, saAccount, topicFoo, subscription) } -func testAccPubsubSubscription_basic(topic, subscription, label string, deadline int) string { +func testAccPubsubSubscription_basic(topic, subscription, label string, deadline int, exactlyOnceDelivery bool) string { return fmt.Sprintf(` resource "google_pubsub_topic" "foo" { name = "%s" @@ -226,8 +226,9 @@ resource "google_pubsub_subscription" "foo" { minimum_backoff = "60.0s" } ack_deadline_seconds = %d + enable_exactly_once_delivery = %t } -`, topic, subscription, label, deadline) +`, topic, subscription, label, deadline, exactlyOnceDelivery) } func testAccPubsubSubscription_topicOnly(topic string) string { diff --git a/website/docs/r/pubsub_subscription.html.markdown b/website/docs/r/pubsub_subscription.html.markdown index c1a3c5aa311..cff313ed6e7 100644 --- a/website/docs/r/pubsub_subscription.html.markdown +++ b/website/docs/r/pubsub_subscription.html.markdown @@ -198,7 +198,7 @@ The following arguments are supported: (Optional) How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published. If - retainAckedMessages is true, then this also configures the retention + retain_acked_messages is true, then this also configures the retention of acknowledged messages, and thus configures how far back in time a subscriptions.seek can be done. Defaults to 7 days. Cannot be more than 7 days (`"604800s"`) or less than 10 minutes (`"600s"`). @@ -254,6 +254,15 @@ The following arguments are supported: the subscribers in the order in which they are received by the Pub/Sub system. Otherwise, they may be delivered in any order. +* `enable_exactly_once_delivery` - + (Optional) + If `true`, Pub/Sub provides the following guarantees for the delivery + of a message with a given value of messageId on this Subscriptions': + - The message sent to a subscriber is guaranteed not to be resent before the message's acknowledgement deadline expires. + - An acknowledged message will not be resent to a subscriber. + Note that subscribers may still receive multiple copies of a message when `enable_exactly_once_delivery` + is true if the message was published multiple times by a publisher client. These copies are considered distinct by Pub/Sub and have distinct messageId values + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used.