Skip to content

Recipes — SNS (pub/sub)

A ground-up, pure-Go SNS built into doze. Create topics and subscriptions, apply message-attribute filter policies, and fan out to SQS queues or HTTP(S) webhooks.

Name the backing sqs instance; doze holds it running while SNS is up and delivers to its queues.

sqs "jobs" {
queue "emails" {}
}
sns "events" {
sqs = sqs.jobs.name # typed reference to the backing SQS instance
topic "signups" {}
subscribe "signups" {
protocol = "sqs"
endpoint = "emails" # the jobs/emails queue (name or queue ARN)
raw = true # raw delivery: body is the message, no envelope
}
}
Terminal window
# SNS and SQS each listen on the explicit port you declared; set both endpoints:
export AWS_ENDPOINT_URL_SNS=http://127.0.0.1:9100
export AWS_ENDPOINT_URL_SQS=http://127.0.0.1:9200
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_REGION=us-east-1
aws sns publish \
--topic-arn arn:aws:sns:us-east-1:000000000000:signups \
--message "welcome!"
# it lands in the jobs/emails queue:
url=$(aws sqs get-queue-url --queue-name emails --query QueueUrl --output text)
aws sqs receive-message --queue-url "$url"

Drop raw = true and the queue receives the standard SNS JSON envelope ({"Type":"Notification","Message":...,"MessageAttributes":...}) instead of the bare body.

A topic can fan out to several queues, each with its own filter. Operators: exact list, prefix, anything-but, exists.

sqs "bus" {
queue "email-svc" {}
queue "audit-svc" {}
}
sns "events" {
sqs = "bus"
topic "user-events" {}
subscribe "user-events" { # only signup/reset events
protocol = "sqs"
endpoint = "email-svc"
raw = true
filter = { type = ["signup", "password_reset"] }
}
subscribe "user-events" { # everything, for the audit log
protocol = "sqs"
endpoint = "audit-svc"
raw = true
}
}
Terminal window
# delivered to email-svc AND audit-svc:
aws sns publish --topic-arn arn:aws:sns:us-east-1:000000000000:user-events \
--message '{"id":1}' \
--message-attributes '{"type":{"DataType":"String","StringValue":"signup"}}'
# delivered to audit-svc only (filtered out of email-svc):
aws sns publish --topic-arn arn:aws:sns:us-east-1:000000000000:user-events \
--message '{"id":2}' \
--message-attributes '{"type":{"DataType":"String","StringValue":"login"}}'

doze runs the SubscriptionConfirmation handshake; your endpoint confirms by fetching the SubscribeURL (or calling ConfirmSubscription), then receives Notification POSTs — perfect for testing webhook handlers locally.

sns "events" {
topic "signups" {}
subscribe "signups" {
protocol = "https"
endpoint = "https://localhost:9000/hooks/sns"
}
}
Terminal window
# Publisher and subscribers read the endpoint + creds from their own env
# (exported as above, or injected via a `process` block); doze ensures SNS is up:
doze run -- ./publisher
doze run -- ./consumer

Go: o.BaseEndpoint = aws.String(os.Getenv("AWS_ENDPOINT_URL_SNS")) Node v3: new SNSClient({ endpoint: process.env.AWS_ENDPOINT_URL_SNS }) boto3: boto3.client("sns", endpoint_url=os.environ["AWS_ENDPOINT_URL_SNS"])

  • Topics/subscriptions declared in config are created on boot (and re-converged by doze sync); you can also Subscribe/Publish dynamically via the SDK.
  • ARNs use the conventional local account 000000000000 and region us-east-1.