-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Sns:v2 publish #13399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sns:v2 publish #13399
Conversation
Test Results - Alternative Providers198 tests 110 ✅ 36s ⏱️ Results for commit e8005bf. ♻️ This comment has been updated with latest results. |
Test Results (amd64) - Integration, Bootstrap 5 files 5 suites 1h 28m 44s ⏱️ Results for commit e8005bf. ♻️ This comment has been updated with latest results. |
LocalStack Community integration with Pro 2 files ± 0 2 suites ±0 1h 0m 40s ⏱️ - 1h 0m 26s Results for commit e8005bf. ± Comparison against base commit fedfb84. This pull request removes 2004 and adds 11 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
bentsku
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! This looks great, loving the changes in the provider 👍 Looks like it was only a limited set of changes.
Are there still some tests failing? Do we have an idea of what it will take to have everything working?
I only have one big comment around the full duplication of publisher.py and of the maintenance burden it could be (looking at the double set of DynamoDB providers and the pain it is, I'm trying to avoid it as much as possible now). I believe it is possible to make the current implementation working with both providers without big trouble, but correct me if I'm wrong! I might be missing something, I tried to diff the files locally to see the difference between the new version here and the current version.
I believe once this is addressed, we're good to go!
| if topic_arn not in store.topics: | ||
| raise NotFoundException("Topic does not exist") | ||
|
|
||
| topic_subscriptions = store.topics[topic_arn]["subscriptions"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: as we are calling self._get_topic a bit under, I think we could save the topic here:
| if not (topic := store.topics.get(topic_arn)): | |
| raise NotFoundException("Topic does not exist") | |
| topic_subscriptions = topic["subscriptions"] |
So that we could reuse the topic at line 393 (to get the attributes)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by calling _get_topic we actually already do that check already, so it eliminates even more code, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked at the diff between the regular publisher.py and this one, and it's only 5 lines differences. I'm not sure it is worth fully copy pasting the file to be honest.
I think the code could be adapted in such a way that it would be compatible with both providers, as the difference is only about the utility to fetch the subscriptions of a topic:
- the models are almost identical and don't have a change in behavior, so they are fine to use which ever version between v1 and v2
- one minor change for the
SignatureVersioncasing, we could try to get both values I think - the new utility to fetch the topic subscriptions could be adapted to also work for the old store, that way you could use that one everywhere (you might have type hints issue but I think it is alright):
def get_topic_subscriptions(store: SnsStore, topic_arn: str) -> list[SnsSubscription]:
# TODO: delete this once the legacy implementation has been removed
if hasattr(store, "topic_subscriptions"):
sub_arns = store.topic_subscriptions.get(topic_arn, [])
else:
sub_arns: list[str] = store.topics[topic_arn].get("subscriptions", [])
subscriptions = [store.subscriptions[k] for k in sub_arns if k in store.subscriptions]
return subscriptionsWhat do you think? I think it would reduce the scope of changes, and make it easier to see the diff of changes, and if one day we need a fix in the publisher while we still have 2 providers, we can fix it in one place only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason why I did this was that if we allow both casings, and then retire the v1 provider at some point, this has high potential to stay. At that point, it is unnecessary at best and a potential bug at worst. Then again, it probably won't have much impact and doesn't compare against 1k line copy pasted. The big question is "how much do we need to change ultimately". If it is 20 lines of codes, it's probably alright to fill the publisher with some legacy code. If it's 100, it's probably better to copy paste it. I will mark that spot with a comment, so if somebody at some point looks for "v1" in the code, they can at least identify the spots easily.
tl;dr: not duplicating the publisher and marking all those spots with comments is probably a good middle ground
bentsku
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I missed something else, it seems we're still trying to access an attribute of the topic via .content_based_deduplication which will fail. Would be good to fix too 👍
| # for compatibility reasons, AWS allows users to use either TargetArn or TopicArn for publishing to a topic | ||
| # use any of them for topic validation | ||
| topic_or_target_arn = topic_arn or target_arn | ||
| topic_model = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I believe we could call this topic here as model was heavily tied with moto, and now it is only a TypedDict
| "Invalid parameter: The MessageGroupId parameter is required for FIFO topics", | ||
| ) | ||
| topic_model = self._get_topic(topic_or_target_arn, context) | ||
| if topic_model.content_based_deduplication == "false": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is a leftover from moto: topic_model is a typed dict and won't have an attribute named content_based_deduplication and it will trigger an AttributeError, sorry for missing it earlier, it's hard with no diff to know what's new to not 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, thanks!
baermat
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bentsku I worked in the suggestions and also realised I failed to actually submit my comments 🤦 please take a look (but it can easily be tackled in a follow up PR)
| # TODO: reintroduce multi-region parameter (latest before final migration from v1) | ||
| @staticmethod | ||
| def _get_topic(arn: str, context: RequestContext) -> Topic: | ||
| def _get_topic(arn: str, context: RequestContext, multi_region: bool = False) -> Topic: | ||
| """ | ||
| :param arn: the Topic ARN | ||
| :param context: the RequestContext of the request | ||
| :return: the model Topic | ||
| """ | ||
| arn_data = parse_and_validate_topic_arn(arn) | ||
| if context.region != arn_data["region"]: | ||
| if not multi_region and context.region != arn_data["region"]: | ||
| raise InvalidParameterException("Invalid parameter: TopicArn") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there is any usage for this with multi_region = True, but @bentsku you disagreed last time, and since I was tackling a failing test that was testing multi region, I tackled this. I don't think the access to the store makes sense, and the current v1 provider runs without it as well. Can you elaborate on where do you think we need to allow multi_region access?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I think it was actually an oversight and a mistake I had done to add it. As you said it's not in the current provider anymore and I'm not sure why I disagreed last time 😅 sorry for that, I think it's safe to remove!
| if topic_arn not in store.topics: | ||
| raise NotFoundException("Topic does not exist") | ||
|
|
||
| topic_subscriptions = store.topics[topic_arn]["subscriptions"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by calling _get_topic we actually already do that check already, so it eliminates even more code, thanks!
| "Invalid parameter: The MessageGroupId parameter is required for FIFO topics", | ||
| ) | ||
| topic_model = self._get_topic(topic_or_target_arn, context) | ||
| if topic_model.content_based_deduplication == "false": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason why I did this was that if we allow both casings, and then retire the v1 provider at some point, this has high potential to stay. At that point, it is unnecessary at best and a potential bug at worst. Then again, it probably won't have much impact and doesn't compare against 1k line copy pasted. The big question is "how much do we need to change ultimately". If it is 20 lines of codes, it's probably alright to fill the publisher with some legacy code. If it's 100, it's probably better to copy paste it. I will mark that spot with a comment, so if somebody at some point looks for "v1" in the code, they can at least identify the spots easily.
tl;dr: not duplicating the publisher and marking all those spots with comments is probably a good middle ground
bentsku
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks a lot for addressing the comment, and good catch on the multi_region parameter, I don't know why I insisted on that 😅 it can be addressed in a follow up too 👍
This looks great! Congrats! 🚀
| # TODO: reintroduce multi-region parameter (latest before final migration from v1) | ||
| @staticmethod | ||
| def _get_topic(arn: str, context: RequestContext) -> Topic: | ||
| def _get_topic(arn: str, context: RequestContext, multi_region: bool = False) -> Topic: | ||
| """ | ||
| :param arn: the Topic ARN | ||
| :param context: the RequestContext of the request | ||
| :return: the model Topic | ||
| """ | ||
| arn_data = parse_and_validate_topic_arn(arn) | ||
| if context.region != arn_data["region"]: | ||
| if not multi_region and context.region != arn_data["region"]: | ||
| raise InvalidParameterException("Invalid parameter: TopicArn") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I think it was actually an oversight and a mistake I had done to add it. As you said it's not in the current provider anymore and I'm not sure why I disagreed last time 😅 sorry for that, I think it's safe to remove!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks a lot for keeping it as one 🙏 I agree this legacy code might stay, we should do somewhat of a checklist of what to delete once we remove the legacy provider to keep track of all clean up we'll need to do (removing the test job, removing this in publisher.py, etc)
Motivation
This PR enables publishing and batch-publishing for the SNS v2 provider. It enables the first skipped tests that relate to publish.
relates to PNX-75
It also adds the code for the raw http certificate response and the publisher.
Changes
Tests
Related