Event-driven architecture on AWS decouples services, handles traffic spikes, and enables workflows that scale automatically. Here is how to build it correctly with SQS, SNS, EventBridge, and Lambda.
Swiggy receives 50,000 orders per minute during the IPL final dinner rush. Each order triggers seven downstream actions: fraud check, restaurant notification, delivery partner assignment, payment processing, inventory update, email confirmation, and analytics write. If the Order Service calls all seven directly and any one of them is slow or unavailable, the user waits. At 50,000 orders per minute, one slow downstream service turns into 50,000 stalled transactions.
Event-driven architecture solves this. The Order Service publishes one event and moves on. Seven subscribers each receive the event and process it independently. If the email service is slow, orders still complete. If analytics is down, payments still work. Each service scales independently based on its own load.
Tight coupling is the root cause. When Service A calls Service B directly, A depends on B's availability, B's latency, and B's capacity.
Synchronous (tightly coupled): Order Service → HTTP call → Fraud Service (300ms) → HTTP call → Restaurant Service (200ms) → HTTP call → Email Service (150ms) → HTTP call → Analytics Service (400ms)Total: 1,050ms before order confirmation + any service can break the chain Asynchronous (event-driven): Order Service → publish event → SNS Topic → done (10ms)Order Service confirms to user immediately Downstream in parallel (invisible to user):Fraud Service ← reads from SQS Queue ARestaurant Svc ← reads from SQS Queue BEmail Service ← reads from SQS Queue CAnalytics ← Kinesis Firehose → S3Event-driven architecture converts sequential serial processing into parallel independent processing.
SQS is the backbone of most event-driven AWS systems. It decouples producers from consumers and absorbs traffic spikes through persistence.
At Razorpay, webhook events from payment gateways arrive in bursts during peak hours. The processing system reads from SQS at a controlled rate, preventing the database from being overwhelmed during spikes.
Standard Queue for high throughput:
## Create a standard SQS queue with DLQaws sqs create-queue \ --queue-name razorpay-webhook-dlq \ --region ap-south-1 aws sqs create-queue \ --queue-name razorpay-webhooks \ --attributes '{ "VisibilityTimeout": "60", "ReceiveMessageWaitTimeSeconds": "20", "RedrivePolicy": "{ \"deadLetterTargetArn\": \"arn:aws:sqs:ap-south-1:123456789012:razorpay-webhook-dlq\", \"maxReceiveCount\":\"3\" }" }' \ --region ap-south-1FIFO Queue for ordered processing:
When processing financial transactions, order matters. A sell before a buy on the same account is a compliance violation. SQS FIFO guarantees strict ordering per Message Group ID.
## Create FIFO queue for trade order processingaws sqs create-queue \ --queue-name zerodha-trade-orders.fifo \ --attributes '{ "FifoQueue": "true", "ContentBasedDeduplication": "true", "VisibilityTimeout": "30" }' \ --region ap-south-1Visibility timeout — get it right:
The visibility timeout is the time a consumer has to process and delete a message before it reappears. Too short means duplicate processing. Too long means slow retry on failure.
Set visibility timeout = 6 × Lambda timeoutLambda timeout: 30 secondsVisibility timeout: 180 seconds minimumSNS delivers one message to all subscribers simultaneously. When an order is placed, every service that cares about the event receives it at the same time.
SNS alone loses messages if a subscriber is down. The production pattern is SNS + SQS — SNS fans out to durable SQS queues:
## Create SNS topic for order eventsaws sns create-topic \ --name swiggy-order-events \ --region ap-south-1 ## Create SQS queues for each downstream serviceaws sqs create-queue \ --queue-name swiggy-fraud-queue \ --region ap-south-1 aws sqs create-queue \ --queue-name swiggy-restaurant-queue \ --region ap-south-1 ## Subscribe each SQS queue to the SNS topicaws sns subscribe \ --topic-arn arn:aws:sns:ap-south-1:123456789012:swiggy-order-events \ --protocol sqs \ --notification-endpoint arn:aws:sqs:ap-south-1:123456789012:swiggy-fraud-queue \ --region ap-south-1 aws sns subscribe \ --topic-arn arn:aws:sns:ap-south-1:123456789012:swiggy-order-events \ --protocol sqs \ --notification-endpoint arn:aws:sqs:ap-south-1:123456789012:swiggy-restaurant-queue \ --region ap-south-1Message filtering — each service gets only what it needs:
## Fraud service only processes high-value ordersaws sns set-subscription-attributes \ --subscription-arn arn:aws:sns:...:fraud-queue-subscription \ --attribute-name FilterPolicy \ --attribute-value '{"orderValue": [{"numeric": [">=", 2000]}]}' \ --region ap-south-1The fraud queue only receives orders above Rs. 2,000. Lower-value orders go directly to fulfilment without fraud review. One topic, intelligent routing.
EventBridge watches every AWS service event and routes them to targets based on rules you define. No polling. No custom integrations. Zero-latency reaction to infrastructure events.
At Zerodha, when a production EC2 instance terminates unexpectedly, an incident is created automatically:
## React to unexpected EC2 terminationaws events put-rule \ --name detect-ec2-termination \ --event-pattern '{ "source": ["aws.ec2"], "detail-type": ["EC2 Instance State-change Notification"], "detail": {"state": ["terminated"]} }' \ --state ENABLED \ --region ap-south-1 ## Route to Lambda for incident creationaws events put-targets \ --rule detect-ec2-termination \ --targets '[{ "Id": "create-incident-lambda", "Arn": "arn:aws:lambda:ap-south-1:123456789012:function:create-pagerduty-incident" }]' \ --region ap-south-1Scheduled triggers — no cron servers:
## Run nightly data cleanup at 2 AM IST (8:30 PM UTC)aws events put-rule \ --name nightly-cleanup \ --schedule-expression "cron(30 20 * * ? *)" \ --state ENABLED \ --region ap-south-1Custom application events:
## Publish custom business events from your applicationaws events put-events \ --entries '[{ "EventBusName": "prod-business-events", "Source": "com.razorpay.payments", "DetailType": "PaymentSucceeded", "Detail": "{ \"paymentId\": \"pay_abc123\", \"amount\": 4500, \"merchantId\": \"merch_xyz789\" }" }]' \ --region ap-south-1For high-volume event streams — clickstream data, IoT sensor readings, financial tick data — Kinesis Data Streams handles what SQS cannot: multiple consumers reading the same stream simultaneously with replay capability.
## Create Kinesis stream for Hotstar clickstreamaws kinesis create-stream \ --stream-name hotstar-clickstream \ --shard-count 10 \ --region ap-south-1 ## Send clickstream eventaws kinesis put-record \ --stream-name hotstar-clickstream \ --partition-key "user-98765" \ --data '{"userId":"user-98765","event":"play","contentId":"match-ipl-2024-01","ts":1704067200}' \ --region ap-south-110 shards:Ingest: 10 MB/s or 10,000 records/secondRead: 20 MB/s (2 MB/s per shard)Multiple Lambda, Flink, and Firehose consumers read simultaneouslyKinesis Data Firehose delivers the stream to S3 for archiving — no consumer code needed:
## Deliver Kinesis stream to S3 in Parquet formataws firehose create-delivery-stream \ --delivery-stream-name hotstar-clicks-to-s3 \ --kinesis-stream-source-configuration \ 'KinesisStreamARN=arn:aws:kinesis:ap-south-1:123456789012:stream/hotstar-clickstream, RoleARN=arn:aws:iam::123456789012:role/FirehoseRole' \ --extended-s3-destination-configuration '{ "BucketARN": "arn:aws:s3:::hotstar-analytics-raw", "Prefix": "clicks/year=!{timestamp:yyyy}/month=!{timestamp:MM}/", "BufferingHints": {"SizeInMBs": 64, "IntervalInSeconds": 60}, "DataFormatConversionConfiguration": { "Enabled": true, "OutputFormatConfiguration": { "Serializer": {"ParquetSerDe": {}} } } }' \ --region ap-south-1Every event-driven system needs a failure path. Messages that fail processing repeatedly go to a Dead Letter Queue for inspection and manual reprocessing.
The complete failure handling flow:
Message arrives in SQS queue ↓Lambda consumer picks it up ↓Processing fails (downstream service down, parsing error, etc.) ↓Message returns to queue (visibility timeout expires) ↓Retried 3 times (maxReceiveCount = 3) ↓Moved to DLQ automatically ↓CloudWatch alarm on DLQ depth → SNS alert → engineer investigates## Alert when messages land in DLQaws cloudwatch put-metric-alarm \ --alarm-name dlq-messages-detected \ --metric-name ApproximateNumberOfMessagesVisible \ --namespace AWS/SQS \ --dimensions Name=QueueName,Value=swiggy-fraud-queue-dlq \ --statistic Sum \ --period 60 \ --threshold 1 \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --alarm-actions arn:aws:sns:ap-south-1:123456789012:devops-alerts \ --region ap-south-1The most powerful pattern for batch and background processing: SQS queue depth drives Auto Scaling Group size automatically.
Orders land in SQS queue ↓CloudWatch monitors ApproximateNumberOfMessages ↓Queue depth > 1,000 → alarm fires → ASG adds 5 EC2 workersQueue depth < 100 → alarm fires → ASG removes workers down to minimum Result: worker fleet automatically matches workload volume3 AM quiet → 2 workers runningDinner rush → 20 workers runningCost tracks workload exactly| Pattern | SQS | SNS | EventBridge | Kinesis |
|---|---|---|---|---|
| Message persistence | Yes — until consumed | No | No | Yes — 1-365 days |
| Consumers per message | One | All subscribers | All matching targets | All shards |
| Replay | No | No | Via archive | Yes |
| AWS event reactions | No | No | Yes — native | No |
| Throughput | Unlimited | Unlimited | Unlimited | Per shard |
| Best for | Work queues | Fan-out notifications | AWS event reactions | High-volume streams |
Follow these patterns to build a resilient event-driven system:
REMEMBER THIS**References and Further Reading** * [Amazon SQS developer guide](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html) — visibility timeout, FIFO, and DLQ patterns * [EventBridge patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html) — event filtering and routing reference * [Kinesis Data Streams vs SQS](https://aws.amazon.com/kinesis/data-streams/faqs/) — AWS's own comparison
SQS FIFO queues provide exactly-once delivery using a Message Deduplication ID — duplicate messages with the same ID within a 5-minute window are automatically discarded. For standard SQS queues which deliver at-least-once, your consumer must be idempotent — processing the same message twice must produce the same result. Use a DynamoDB conditional write or a unique constraint check as a deduplication mechanism in your consumer code.
SQS is a queue — messages persist until a consumer reads and deletes them, and each message goes to one consumer. EventBridge is an event router — it delivers events to multiple targets simultaneously based on rules, with no persistent storage. Use SQS when you need guaranteed delivery, at-least-once processing, and a work queue pattern. Use EventBridge when you need to react to AWS service events, route events to multiple targets based on content, or trigger scheduled tasks.
Discussion0