Skip to content

Conversation

@rlaunch
Copy link

@rlaunch rlaunch commented Oct 3, 2025

RECREATED for #2339

This PR enhances the existing SNS support by adding fanout support using AWS SNS. Some existing SNS channel methods have been refactored to allow for easier re-use between SNS & SQS services.

As the Channel class was becoming somewhat sprawling, SNS support was added through composition in a subclass and is only initialised upon use of a fanout function.

To avoid breaking changes, 'supports_fanout' has been left as False by default, but can be enabled via transport_options.

@auvipy auvipy added this to the 5.7.0 milestone Oct 4, 2025
@Nusnus Nusnus marked this pull request as draft October 8, 2025 01:01
Ryan Launchbury and others added 3 commits October 9, 2025 09:30
@rlaunch rlaunch marked this pull request as ready for review October 14, 2025 07:10
@rlaunch rlaunch requested a review from auvipy October 20, 2025 07:25
@rlaunch
Copy link
Author

rlaunch commented Oct 23, 2025

Hey @auvipy,

Thanks for checking in on this PR. I have addressed the issues raised by the CI pipeline.
It seems after merging master into this branch, unit tests are failing for modules that have not been changed as part of this PR. Potentially a flakey test as it only affected one version of Python.

Please let me know if you need any further changes.

Best,
Ryan

@auvipy auvipy requested a review from Copilot October 25, 2025 04:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds SNS fanout support to the AWS SQS transport, enabling fanout exchanges to publish messages to multiple SQS queues via AWS SNS topics. The implementation introduces SNS topic management, queue subscriptions, and stale subscription cleanup while maintaining backward compatibility.

Key changes:

  • Added SNS fanout functionality through a new SNS class with topic and subscription management
  • Refactored STS token handling into reusable methods shared between SQS and SNS services
  • Introduced predefined exchanges configuration to complement existing predefined queues

Reviewed Changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
kombu/transport/SQS/init.py Core integration of SNS fanout with SQS transport, including fanout exchange detection, queue subscription, and refactored STS token handling
kombu/transport/SQS/SNS.py New module implementing SNS topic creation, message publishing, and subscription management
kombu/transport/SQS/exceptions.py Moved exception classes to dedicated module for better organization
t/unit/transport/SQS/conftest.py Centralized test fixtures and example data for SQS and SNS tests
t/unit/transport/SQS/test_SQS_SNS.py Comprehensive test suite for SNS fanout functionality
t/unit/transport/SQS/test_SQS.py Updated tests with fanout integration and refactored for shared fixtures
docs/reference/kombu.transport.SQS.rst Documentation for new SNS and exceptions modules
README.rst Updated transport comparison to reflect SNS-based fanout implementation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +400 to +414
assert (
sns_fanout._create_boto_client.call_args_list
== [
call(
region="some-aws-region",
access_key_id="MyAccessKeyID",
secret_access_key="MySecretAccessKey",
)
]
!= [
call(
region="some-aws-region", access_key_id=None, secret_access_key=None
)
]
)
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion logic is incorrect. The expression (X == Y) != Z always evaluates based on the inequality comparison, making the equality check meaningless. This should likely be just assert sns_fanout._create_boto_client.call_args_list == [call(...)] without the chained inequality.

Suggested change
assert (
sns_fanout._create_boto_client.call_args_list
== [
call(
region="some-aws-region",
access_key_id="MyAccessKeyID",
secret_access_key="MySecretAccessKey",
)
]
!= [
call(
region="some-aws-region", access_key_id=None, secret_access_key=None
)
]
)
assert sns_fanout._create_boto_client.call_args_list == [
call(
region="some-aws-region",
access_key_id="MyAccessKeyID",
secret_access_key="MySecretAccessKey",
)
]
assert sns_fanout._create_boto_client.call_args_list != [
call(
region="some-aws-region", access_key_id=None, secret_access_key=None
)
]

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please cross check this suggestion

client_kwargs['endpoint_url'] = self.endpoint_url
client_config = self.transport_options.get('client-config') or {}
config = Config(**client_config)
return session.client('sqs', config=config, **client_kwargs)
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service parameter is hardcoded to 'sqs' instead of using the service parameter from the method signature. This breaks SNS client creation when called with service="sns". Change to return session.client(service, config=config, **client_kwargs).

Suggested change
return session.client('sqs', config=config, **client_kwargs)
return session.client(service, config=config, **client_kwargs)

Copilot uses AI. Check for mistakes.
'MessageSystemAttributeNames': (
sorted(message_system_attrs) if message_system_attrs else [APPROXIMATE_RECEIVE_COUNT]
)
"MessageAttributeNames": sorted(message_attrs) if message_attrs else [],
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the return value from None to [] when message_attrs is empty, which may break existing code expecting None. The original code returned None in this case (line 1137 in the old version).

Suggested change
"MessageAttributeNames": sorted(message_attrs) if message_attrs else [],
"MessageAttributeNames": sorted(message_attrs) if message_attrs else None,

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants