Reputation: 1443
The Problem
An SNS Topic running in a LocalStack Container will send a notification to a subscribed HTTP endpoint running in a separate container, but the API receives {}
instead of the message sent to SNS.
Steps To Reproduce
For brevity I excluded the my-api
Dockerfile and App code. You can fill in any web server (FastAPI, Express etc.) just so long as it listens on Port 3000, and has a POST /events
endpoint. There's nothing special going on in that API right now on my end, it simply logs the event received.
docker-compose.yml
fileversion: '3.8'
services:
my-api:
build:
context: .
ports:
- 3000:3000
volumes:
- ./src:/opt/my-api/src
localstack:
image: localstack/localstack
container_name: localstack
ports:
- 4566:4566
environment:
- SERVICES=sns
- AWS_DEFAULT_REGION=us-east-1
volumes:
- localstack-data:/var/lib/localstack
# https://docs.localstack.cloud/references/init-hooks/
- ./localstack-init-scripts/:/etc/localstack/init/ready.d/
volumes:
localstack-data:
localstack-init-scripts/init.py
Python script for initializing the LocalStack container.import boto3
import requests
# SNS Client
sns = boto3.client('sns', endpoint_url='http://localhost:4566', region_name='us-east-1')
# Create Topic
topic_arn = sns.create_topic(Name='local-events')['TopicArn']
print('Topic Arn:', topic_arn)
#Subscribe HTTP endpoint to Topic
subscription_arn = sns.subscribe(
TopicArn=topic_arn,
Protocol='http',
Endpoint='http://host.docker.internal:3000/events',
# I've also tried Endpoint='http://my-api:3000/events',
ReturnSubscriptionArn=True
)['SubscriptionArn']
print('Subscription Arn:', subscription_arn)
# Get the Subscription Token and Confirm the Subscription
token_res = requests.get(f'http://localhost:4566/_aws/sns/subscription-tokens/{subscription_arn}').json()
print('Token Res:', token_res)
confirmation_status_code = sns.confirm_subscription(
TopicArn=topic_arn,
Token=token_res['subscription_token']
).get('ResponseMetadata', {}).get('HTTPStatusCode', 500)
confirmed = True if confirmation_status_code == 200 else False
print('Subscription Confirmed:', confirmed)
docker compose up
local-events
Topicaws --endpoint-url http://localhost:4566 sns publish \
--topic-arn arn:aws:sns:us-east-1:000000000000:local-events \
--message '{ "msg": "This is a Test Message" }'
Results
After running the above commands you should see docker logs similar to
localstack | 2024-10-01T01:38:29.993 INFO --- [et.reactor-0] localstack.request.aws : AWS sns.CreateTopic => 200
localstack | Topic Arn: arn:aws:sns:us-east-1:000000000000:local-events
localstack | 2024-10-01T01:38:29.997 INFO --- [et.reactor-0] localstack.request.aws : AWS sns.Subscribe => 200
localstack | Subscription Arn: arn:aws:sns:us-east-1:000000000000:local-events:e98cb2ad-565c-4160-a77c-6a4bdd21350f
localstack | 2024-10-01T01:38:30.001 INFO --- [et.reactor-0] localstack.request.http : GET /_aws/sns/subscription-tokens/arn:aws:sns:us-east-1:000000000000:local-events:e98cb2ad-565c-4160-a77c-6a4bdd21350f => 200
localstack | Token Res: {'subscription_token': '75732d656173742d312f8c8e1e8b8c8e1e8b8c8e1e8b8c8e1e8b8c8e1e8b8c8e', 'subscription_arn': 'arn:aws:sns:us-east-1:000000000000:local-events:e98cb2ad-565c-4160-a77c-6a4bdd21350f'}
localstack | 2024-10-01T01:38:30.004 INFO --- [et.reactor-0] localstack.request.aws : AWS sns.ConfirmSubscription => 200
localstack | Subscription Confirmed: True
localstack | Ready.
my-api-1 | Received event {}
Troubleshooting Steps ~~so far~~
curl -XPOST http://host.docker.internal:3000/events -d '{ "msg": "curl test message" }'
I get back the expected response and see the following in the docker logsmy-api-1 | Received event { '{ "msg": "curl test message" }': '' }
awslocal sns get-subscription-attributes --subscription-arn "<subscription-arn-from-logs>"
and got back a response with "ConfirmationWasAuthenticated": "true"
and "PendingConfirmation": "false"
References
Upvotes: 0
Views: 160