Messaging Deep Dive Basics
Seven examples that build a working SNS-to-SQS fan-out from scratch - five basic and two intermediate.
Busque em todas as páginas da documentação
Seven examples that build a working SNS-to-SQS fan-out from scratch - five basic and two intermediate.
Each example shows the same operation in both Python (boto3) and TypeScript (AWS SDK for JavaScript v3).
pip install boto3 (boto3 1.43.x, Python 3.10+). TypeScript: npm install @aws-sdk/client-sns @aws-sdk/client-sqs (Node.js 18+).sns:* and sqs:* on the resources you create.AWS_REGION or passed per client.Start with one SNS topic and two independent SQS queues that will each get a copy of every message.
# --- Python (boto3) ---
import boto3
sns = boto3.client("sns", region_name="us-east-1")
sqs = boto3.client("sqs", region_name="us-east-1")
topic_arn = sns.create_topic(Name="order-events")["TopicArn"]
billing_url = sqs.create_queue(QueueName="billing-queue")["QueueUrl"]
shipping_url = sqs.create_queue(QueueName="shipping-queue")["QueueUrl"]// --- TypeScript (AWS SDK v3) ---
import { SNSClient, CreateTopicCommand } from "@aws-sdk/client-sns";
import { SQSClient, CreateQueueCommand } from "@aws-sdk/client-sqs";
const sns = new SNSClient({ region: "us-east-1" });
const sqs = new SQSClient({ region: "us-east-1" });
const { TopicArn } = await sns.send(new CreateTopicCommand({ Name: "order-events" }));
const billing = await sqs.send(new CreateQueueCommand({ QueueName: "billing-queue" }));
const shipping = await sqs.send(new CreateQueueCommand({ QueueName: "shipping-queue" }));CreateTopic and CreateQueue are both idempotent for the same name and attributes.billing-queue, shipping-queue) keeps ownership obvious.Related: SNS & SQS Together: Fan-Out Messaging - the pattern this builds.
Subscriptions need a queue's ARN, not its URL, so fetch it with GetQueueAttributes.
# --- Python (boto3) ---
billing_arn = sqs.get_queue_attributes(
QueueUrl=billing_url, AttributeNames=["QueueArn"])["Attributes"]["QueueArn"]
shipping_arn = sqs.get_queue_attributes(
QueueUrl=shipping_url, AttributeNames=["QueueArn"])["Attributes"]["QueueArn"]// --- TypeScript (AWS SDK v3) ---
import { GetQueueAttributesCommand } from "@aws-sdk/client-sqs";
const billingAttrs = await sqs.send(new GetQueueAttributesCommand({
QueueUrl: billing.QueueUrl, AttributeNames: ["QueueArn"],
}));
const shippingAttrs = await sqs.send(new GetQueueAttributesCommand({
QueueUrl: shipping.QueueUrl, AttributeNames: ["QueueArn"],
}));SendMessage/ReceiveMessage; the ARN identifies it for permissions and subscriptions.GetQueueAttributes accepts a list of attribute names, so request only QueueArn when that is all you need.Each queue must explicitly allow the SNS service to call SendMessage on it.
# --- Python (boto3) ---
import json
def allow_sns(queue_url, queue_arn, topic_arn):
policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow", "Principal": {"Service": "sns.amazonaws.com"},
"Action": "sqs:SendMessage", "Resource": queue_arn,
"Condition": {"ArnEquals": {"aws:SourceArn": topic_arn}},
}],
}
sqs.set_queue_attributes(QueueUrl=queue_url, Attributes={"Policy": json.dumps(policy)})
allow_sns(billing_url, billing_arn, topic_arn)
allow_sns(shipping_url, shipping_arn, topic_arn)// --- TypeScript (AWS SDK v3) ---
import { SetQueueAttributesCommand } from "@aws-sdk/client-sqs";
async function allowSns(queueUrl: string, queueArn: string, topicArn: string) {
const policy = {
Version: "2012-10-17",
Statement: [{
Effect: "Allow", Principal: { Service: "sns.amazonaws.com" },
Action: "sqs:SendMessage", Resource: queueArn,
Condition: { ArnEquals: { "aws:SourceArn": topicArn } },
}],
};
await sqs.send(new SetQueueAttributesCommand({
QueueUrl: queueUrl, Attributes: { Policy: JSON.stringify(policy) },
}));
}
await allowSns(billing.QueueUrl!, billingAttrs.Attributes!.QueueArn, TopicArn!);
await allowSns(shipping.QueueUrl!, shippingAttrs.Attributes!.QueueArn, TopicArn!);Publish call still reports success.aws:SourceArn restricts writes to this specific topic, not every SNS topic in the account.SetQueueAttributes.Create the subscriptions using each queue's ARN as the endpoint.
# --- Python (boto3) ---
sns.subscribe(TopicArn=topic_arn, Protocol="sqs", Endpoint=billing_arn)
sns.subscribe(TopicArn=topic_arn, Protocol="sqs", Endpoint=shipping_arn)// --- TypeScript (AWS SDK v3) ---
import { SubscribeCommand } from "@aws-sdk/client-sns";
await sns.send(new SubscribeCommand({ TopicArn, Protocol: "sqs", Endpoint: billingAttrs.Attributes!.QueueArn }));
await sns.send(new SubscribeCommand({ TopicArn, Protocol: "sqs", Endpoint: shippingAttrs.Attributes!.QueueArn }));PendingConfirmation state to wait out.Subscribe returns a SubscriptionArn you can use later to set a filter policy or unsubscribe.A single publish reaches both queues; drain each independently.
# --- Python (boto3) ---
sns.publish(TopicArn=topic_arn, Subject="Order placed", Message="order o-100 placed")
for url in (billing_url, shipping_url):
resp = sqs.receive_message(QueueUrl=url, WaitTimeSeconds=5)
for m in resp.get("Messages", []):
print(url, "got", m["Body"])
sqs.delete_message(QueueUrl=url, ReceiptHandle=m["ReceiptHandle"])// --- TypeScript (AWS SDK v3) ---
import { PublishCommand } from "@aws-sdk/client-sns";
import { ReceiveMessageCommand, DeleteMessageCommand } from "@aws-sdk/client-sqs";
await sns.send(new PublishCommand({ TopicArn, Subject: "Order placed", Message: "order o-100 placed" }));
for (const url of [billing.QueueUrl, shipping.QueueUrl]) {
const resp = await sqs.send(new ReceiveMessageCommand({ QueueUrl: url, WaitTimeSeconds: 5 }));
for (const m of resp.Messages ?? []) {
console.log(url, "got", m.Body);
await sqs.send(new DeleteMessageCommand({ QueueUrl: url, ReceiptHandle: m.ReceiptHandle! }));
}
}Message, MessageId, and TopicArn fields.By default the queue body is a JSON wrapper around your message; raw delivery removes it.
# --- Python (boto3) ---
sub_arn = sns.subscribe(TopicArn=topic_arn, Protocol="sqs", Endpoint=billing_arn)["SubscriptionArn"]
sns.set_subscription_attributes(
SubscriptionArn=sub_arn, AttributeName="RawMessageDelivery", AttributeValue="true")// --- TypeScript (AWS SDK v3) ---
import { SetSubscriptionAttributesCommand } from "@aws-sdk/client-sns";
const sub = await sns.send(new SubscribeCommand({ TopicArn, Protocol: "sqs", Endpoint: billingAttrs.Attributes!.QueueArn }));
await sns.send(new SetSubscriptionAttributesCommand({
SubscriptionArn: sub.SubscriptionArn, AttributeName: "RawMessageDelivery", AttributeValue: "true",
}));Body in the receive response is your original message text, not an SNS envelope.Delete subscriptions implicitly by deleting the topic, then delete the queues.
# --- Python (boto3) ---
sns.delete_topic(TopicArn=topic_arn)
sqs.delete_queue(QueueUrl=billing_url)
sqs.delete_queue(QueueUrl=shipping_url)// --- TypeScript (AWS SDK v3) ---
import { DeleteTopicCommand } from "@aws-sdk/client-sns";
import { DeleteQueueCommand } from "@aws-sdk/client-sqs";
await sns.send(new DeleteTopicCommand({ TopicArn }));
await sqs.send(new DeleteQueueCommand({ QueueUrl: billing.QueueUrl }));
await sqs.send(new DeleteQueueCommand({ QueueUrl: shipping.QueueUrl }));Related: Message Filtering with SNS Subscription Filters - route only some messages to each queue.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 25 de jul. de 2026