feat(sns): read-first subscription reconciliation with typed managedAttributes - #618
Conversation
assertSubscription now looks up an existing subscription and reads its attributes before doing anything. When they already match the config, no Subscribe or SetSubscriptionAttributes call is made. Otherwise only the differing attributes are written (or an error is thrown when updateAttributesIfExists is off). The locateOnly path gets the same read-first behaviour through setSubscriptionAttributes. Adds subscriptionConfig.manageOnlyFilterPolicy, which limits checking and writing to FilterPolicy and FilterPolicyScope.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
subscriptionConfig.managedAttributes lists the subscription attributes the application owns, defaulting to FilterPolicy, FilterPolicyScope, RawMessageDelivery and RedrivePolicy. A managed attribute missing from Attributes is now reset on the existing subscription, unmanaged ones are never read or written, and configuring an unmanaged one throws. The consumer DLQ RedrivePolicy write goes through the read-first setSubscriptionAttributes and RedrivePolicy is excluded from the managed set when reuseConsumerDeadLetterQueue is on, so the two never fight over it.
LocalStack rejects any RedrivePolicy that is not a policy with a valid deadLetterTargetArn, so it cannot remove one. The reset test no longer sets RedrivePolicy, and its removal is covered by a separate test that runs on fauxqs only.
Real AWS rejects SetSubscriptionAttributes with an empty RedrivePolicy;
the attribute is removed by leaving AttributeValue out, which is what
the Terraform AWS provider does. FilterPolicy is reset with "{}" as in
the SNS docs.
|
Merging this on #608 to trigger a single release and ask facilitate review of the new feature |
* feat: adding subscription locateOnly mode * Adding deprecation notice * Improve validation to avoid locate only subscription when creating topic and queue (not possible) * Adding tests to cover changes * readme update * readme fix * feat(sns): read-first subscription reconciliation with typed managedAttributes (#618) * feat(sns): check subscription attributes before writing them assertSubscription now looks up an existing subscription and reads its attributes before doing anything. When they already match the config, no Subscribe or SetSubscriptionAttributes call is made. Otherwise only the differing attributes are written (or an error is thrown when updateAttributesIfExists is off). The locateOnly path gets the same read-first behaviour through setSubscriptionAttributes. Adds subscriptionConfig.manageOnlyFilterPolicy, which limits checking and writing to FilterPolicy and FilterPolicyScope. * feat(sns): replace manageOnlyFilterPolicy with typed managedAttributes subscriptionConfig.managedAttributes lists the subscription attributes the application owns, defaulting to FilterPolicy, FilterPolicyScope, RawMessageDelivery and RedrivePolicy. A managed attribute missing from Attributes is now reset on the existing subscription, unmanaged ones are never read or written, and configuring an unmanaged one throws. The consumer DLQ RedrivePolicy write goes through the read-first setSubscriptionAttributes and RedrivePolicy is excluded from the managed set when reuseConsumerDeadLetterQueue is on, so the two never fight over it. * test(sns): skip redrive policy removal on localstack LocalStack rejects any RedrivePolicy that is not a policy with a valid deadLetterTargetArn, so it cannot remove one. The reset test no longer sets RedrivePolicy, and its removal is covered by a separate test that runs on fauxqs only. * fix(sns): remove RedrivePolicy by omitting its value Real AWS rejects SetSubscriptionAttributes with an empty RedrivePolicy; the attribute is removed by leaving AttributeValue out, which is what the Terraform AWS provider does. FilterPolicy is reset with "{}" as in the SNS docs. * chore: fauxqs bump * readme fix --------- Co-authored-by: Igor Savin <iselwin@gmail.com>
Every consumer
init()wrote to its subscription even when nothing had changed:Subscribeon the creation path, and oneSetSubscriptionAttributesper attribute on thelocateOnlypath and for the reused DLQ. There was also no way to say which attributes the application owns, so an attribute removed from the config stayed on the subscription forever. This PR reads first, writes only what differs, and adds a typedmanagedAttributeslist.Stacked on #608, so merge that one first.
Changes
assertSubscriptionlooks up the existing subscription (ListSubscriptionsByTopic) and reads its attributes (GetSubscriptionAttributes). If everything matches, it returns without writing. If something differs, it writes only those attributes whenupdateAttributesIfExistsis on, and throws otherwise. The error lists the differing attribute names.Subscribeis only called when no confirmed subscription exists. If it then fails with "already exists with different attributes" (another instance won the race), the subscription is reconciled the same way as above.subscriptionConfig.managedAttributes?: SubscriptionManagedAttributeName[]on both the creation and thelocateOnlyvariants. It defaults to all ofFilterPolicy,FilterPolicyScope,RawMessageDeliveryandRedrivePolicy.Attributesis reset.FilterPolicyis set to{}(as in the SNS docs).RedrivePolicyis removed by leavingAttributeValueout, because AWS rejects an empty string for it (the Terraform provider does the same). The other two go back toMessageAttributesandfalse.Attributesthrowsinvalid_subscription_configuration.setSubscriptionAttributes(used bylocateOnly) applies the same read-first logic and runs even whenAttributesis empty, so resets also happen in locate mode.RedrivePolicywrite goes throughsetSubscriptionAttributes. WithreuseConsumerDeadLetterQueue,RedrivePolicyis removed from the managed set. Without that, the subscription step would clear it and the DLQ step would set it again on every startup. Managing it explicitly alongside that flag throws.Decisions
Attributes(e.g.ReplayPolicy) are still compared and written when present, but never reset."", the default value, and{}forFilterPolicyall count as unset.FilterPolicyScopeis not reset on its own when the subscription ends up without a filter policy. On its own, the scope has no effect.Risk
RawMessageDeliveryorRedrivePolicyset by Terraform) are now reset whenupdateAttributesIfExistsis on. When it is off, startup fails instead. This also coverslocateOnlyconfigs withoutAttributes. Services that share ownership with Terraform needmanagedAttributes: ['FilterPolicy', 'FilterPolicyScope']before upgrading.ListSubscriptionsByTopic(30 TPS per account) before anything else. Many consumers starting at once against topics with many subscriptions could hit throttling sooner than before.updateAttributesIfExistsis off, the error message for differing attributes changes. The error codesns_subscription_creation_failedstays the same.RedrivePolicycan't be tested on localstack, which rejects both an empty and an omitted value, so that test runs on fauxqs only. The reset values follow the AWS docs and the Terraform provider, but haven't been run against real AWS.