Integrating Services (S3, SNS, SQS)
The Serverless Stack
Most serverless applications combine multiple AWS services:
Simple Explanation
What it is
This lesson shows how to connect storage, messaging, and compute so your app can move data and trigger work across services.
Why we need it
Real serverless apps are never one service. You need storage for files, queues for background work, and notifications for users.
Benefits
- Clear separation of responsibilities across services.
- Better resilience because queues absorb spikes.
- Easier scaling as each service grows independently.
Tradeoffs
- More services to manage and monitor.
- More permissions to configure correctly.
Real-world examples (architecture only)
- Upload image → S3 → Lambda → Thumbnail → SNS notification.
- API request → Lambda → SQS → Worker function.
S3: File Storage
Why S3?
- Unlimited file storage
- Serverless (no servers to manage)
- Highly available
- Pay for storage, not instances
S3 Operations from Lambda
Upload File
import boto3
s3 = boto3.client("s3")
def handler(event, context):
buffer = file_data.encode("utf-8")
s3.put_object(
Bucket="my-bucket",
Key="path/to/file.txt",
Body=buffer,
ContentType="text/plain",
)
return {"statusCode": 200}
Download File
def handler(event, context):
response = s3.get_object(Bucket="my-bucket", Key="path/to/file.txt")
data = response["Body"].read().decode("utf-8")
print("File content:", data)
return {"statusCode": 200, "body": data}
Generate Presigned URL
Let users download files without exposing S3 directly:
import json
from boto3.session import Session
from botocore.client import Config
def handler(event, context):
url = s3.generate_presigned_url(
ClientMethod="get_object",
Params={"Bucket": "my-bucket", "Key": "private-file.pdf"},
ExpiresIn=3600,
)
return {"statusCode": 200, "body": json.dumps({"downloadUrl": url})}
SNS: Publishing Messages
SNS broadcasts messages to multiple subscribers (email, SMS, HTTP, Lambda).
Send Email Notification
import boto3
sns = boto3.client("sns")
def handler(event, context):
sns.publish(
TopicArn="arn:aws:sns:us-east-1:123456:notifications",
Subject="New Order",
Message=f"Order #{order_id} confirmed!",
)
return {"statusCode": 200}
Setup SNS Topic
- Go to SNS Console
- Click Create topic
- Name:
notifications - Under Subscriptions, add email
- Confirm email
SQS: Async Processing
SQS stores messages for Lambda to process asynchronously.
Why SQS?
- Decouple producers from consumers
- Retry failed messages
- Handle traffic spikes
- Guaranteed delivery
Send Message to Queue
import json
import boto3
from datetime import datetime
sqs = boto3.client("sqs")
def handler(event, context):
sqs.send_message(
QueueUrl="https://sqs.us-east-1.amazonaws.com/123456/my-queue",
MessageBody=json.dumps({
"userId": "123",
"action": "process-report",
"timestamp": datetime.utcnow().isoformat(),
}),
)
return {"statusCode": 200}
Process Queue Messages
import json
def handler(event, context):
for record in event.get("Records", []):
message = json.loads(record["body"])
print("Processing:", message)
try:
process_report(message)
except Exception as exc:
print(f"Failed: {exc}")
raise exc
Combining Services: Real Example
Scenario: User uploads image → Generate thumbnail → Send notification
Architecture
Upload API
↓
S3 (stores original image)
↓
Lambda (triggered by S3 upload)
↓
Process image → Generate thumbnail
↓
Save thumbnail to S3
↓
Update DynamoDB
↓
Publish to SNS
↓
User gets email notification
Lambda Handler
import boto3
from datetime import datetime
s3 = boto3.client("s3")
sns = boto3.client("sns")
ddb = boto3.resource("dynamodb").Table("ImageMetadata")
def handler(event, context):
try:
bucket = event["Records"][0]["s3"]["bucket"]["name"]
key = event["Records"][0]["s3"]["object"]["key"]
image_data = s3.get_object(Bucket=bucket, Key=key)["Body"].read()
thumbnail = generate_thumbnail(image_data)
s3.put_object(Bucket=bucket, Key=f"thumbnails/{key}", Body=thumbnail)
ddb.update_item(
Key={"imageId": key},
UpdateExpression="SET thumbnailGenerated = :now",
ExpressionAttributeValues={":now": datetime.utcnow().isoformat()},
)
sns.publish(
TopicArn="arn:aws:sns:...",
Subject="Thumbnail Ready",
Message=f"Your thumbnail is ready: {key}",
)
return {"statusCode": 200, "message": "Processed"}
except Exception as exc:
print(exc)
raise exc
IAM Permissions Template
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Effect": "Allow",
"Action": ["sns:Publish"],
"Resource": "arn:aws:sns:*:*:*"
},
{
"Effect": "Allow",
"Action": ["sqs:SendMessage"],
"Resource": "arn:aws:sqs:*:*:*"
},
{
"Effect": "Allow",
"Action": ["dynamodb:*"],
"Resource": "arn:aws:dynamodb:*:*:table/*"
}
]
}
Best Practices
- Use SQS for heavy lifting — Don't block API responses
- Publish to SNS for fanout — Multiple services react to one event
- Store files in S3 — Not in Lambda memory or DynamoDB
- Presigned URLs — Let users access S3 securely
- Error handling — Use DLQs and retries
Hands-On: Document Processing Pipeline
Build a workflow:
- User uploads PDF to S3
- Lambda triggered automatically
- Extract text and metadata
- Store metadata in DynamoDB
- Send confirmation SNS email
Key Takeaway
AWS services work together through well-defined interfaces. S3 stores, SNS broadcasts, SQS queues. Combine them to build scalable serverless systems.
Project (Cloud-Agnostic)
Design a file-processing pipeline with storage, async processing, and notification.
Deliverables:
- Describe the vendor-neutral architecture (storage, compute, messaging, data).
- Map each component to AWS or GCP services.
- Explain how failures are retried and observed.
If you want feedback, email your write-up to [email protected].
References
- AWS S3: https://docs.aws.amazon.com/s3/
- AWS SNS: https://docs.aws.amazon.com/sns/
- AWS SQS: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/welcome.html
- AWS Lambda Developer Guide: https://docs.aws.amazon.com/lambda/latest/dg/welcome.html
- Google Cloud Storage: https://cloud.google.com/storage/docs
- Google Cloud Pub/Sub: https://cloud.google.com/pubsub/docs/overview