Handbooks / AWS / Chapter 5

Lambda and Serverless

7 pages · ~5 min✓ Reviewed

Builds on RDS and DynamoDB.

AWSPage 1

Lambda Execution Model

1. What Lambda Is

  • One function run per event, in a managed execution environment
  • Pay per request and per GB-second
  • No servers to manage

2. Handler and Lifecycle

python
def handler(event, context):
    left = context.get_remaining_time_in_millis()
    return {"left_ms": left}

event = trigger JSON; context = request ID, time left, memory

  1. Initdownload code, start runtime, run outside-handler code
  2. Invokerun handler
  3. Shutdownenvironment freed
  • Warm environment is reused, so Init is skipped
  • Code outside the handler runs once per environment

3. Invocation Types

TypeCaller waitsRetriesExample
Synchronousyesthe callerAPI Gateway
Asynchronousno, queuedLambda, twiceS3, SNS
Event source mappingno, polledqueue or streamSQS, Kinesis, DynamoDB Streams
AWSPage 2

Cold Starts, Timeouts and Memory

1. Cold vs warm

  • Cold start = new environment, runs Init first
  • Warm start = reuses an environment, skips Init
  • Hits: first call after idle, scale-out bursts, new deployments

2. Reduce cold starts

  • Smaller packages
  • Node, Python, Go start faster than JVM
  • Init SDK clients outside the handler
  • SnapStart: Java, Python, .NET
  • Provisioned concurrency keeps environments warm
python
s3 = boto3.client("s3")  # module level, once per environment

3. Memory and timeout

LimitValue
Lambda timeout3 s default, 15 min max
REST API29 s default, raise by quota
HTTP API30 s max
  • Memory 128 to 10,240 MB; CPU scales with it
  • More memory = shorter duration, often lower cost
  • Tune with Lambda Power Tuning
Timeout trap

A 15 min function behind a default API fails at 29 s.

AWSPage 3

Triggers and API Gateway

1. Triggers

TriggerInvocation
API Gatewaysync
S3, SNS, EventBridge rules and schedulesasync
SQS, Kinesis, DynamoDB Streamspolling

2. API Gateway types

HTTP APIREST APIWebSocket API
Pickcheaper, lower latency, simplerfull feature settwo-way connections
HasJWT authAPI keys, usage plans, validation, WAF, cachingpersistent sockets

3. Proxy and auth

  • Event = the whole request
  • Return {statusCode, headers, body}; body is a string
  • Gateway does auth (IAM, Cognito, Lambda authorizer), throttling, CORS, stages
python
import json
def handler(event, context):
    return {"statusCode": 200,
        "headers": {"Access-Control-Allow-Origin": "*"},
        "body": json.dumps({"ok": True})}
CORS

In proxy mode the function must return the CORS headers too.

4. Interview Point

  • HTTP or REST? HTTP for simple cheap APIs; REST for API keys, usage plans, WAF, caching
  • Proxy response shape? {statusCode, headers, body}, body a string
  • Auth before Lambda? IAM, Cognito or Lambda authorizer; rejected calls never reach it
AWSPage 4

SQS, SNS and EventBridge

1. SQS Buffers Work

  • Pull queue that buffers work; Lambda polls it
  • Batch size: default 10, up to 10,000 standard, 10 FIFO
  • Failed message returns after the visibility timeout

2. SNS and EventBridge

  • SNS: push fan-out, one publish reaches Lambda, SQS, HTTP, email
  • Filter policies: each subscriber gets only matching messages
  • EventBridge: rule patterns on a bus route events to targets
  • Also cron/rate schedules, SaaS and AWS events, schema-based filtering

3. Choosing

ModelUse for
SQSPull queueDecouple, absorb spikes
SNSPush fan-outBroadcast
EventBridgeBus + rulesRoute by content
  1. Publish
  2. SNS topic
  3. SQS queues
  4. Lambda
Combine them

SNS fan-out into SQS queues: broadcast plus per-consumer buffering and retries.

AWSPage 5

When Not to Use Serverless and Common Mistakes

1. Poor Fit

NeedWhy not LambdaUse
Job over 15 min15 min timeout capcontainers
Steady high loadper-request cost adds upcontainers or EC2
Low latencycold startscontainers
Large or GPU10,240 MB cap, no GPUEC2

2. Common Mistakes

  • Function triggers itself, or two trigger each other: set reserved concurrency and a billing alarm
  • DB connection per invocation exhausts the DB: use RDS Proxy or a pool outside the handler
  • /tmp and globals may vanish: keep state in S3 or DynamoDB
  • Retries and SQS deliver at least once: make handlers idempotent
python
conn = pymysql.connect(host=PROXY_HOST)

def handler(event, context):
    with conn.cursor() as cur:
        cur.execute("SELECT * FROM orders WHERE id = %s",
                    (event["id"],))
        return cur.fetchone()

connect once per environment, outside the handler

3. Remember

Idempotent

The same event twice must give the same result. Use an idempotency key, such as the order ID.

AWSPage 6

Serverless Cheat Sheet

1. Limits

LimitValue
Function timeout15 min
Memory128 MB to 10,240 MB
API Gateway timeout29 s
Async retries2
SQS batch10 default, up to 10,000 standard, 10 FIFO

2. Invocation and Cold Starts

InvocationWho retries
Syncthe caller
AsyncLambda, then DLQ or destination
Pollingqueue or stream redelivers
  • SnapStart: Java, Python, .NET
  • Provisioned concurrency
  • Small packages
  • Init clients outside the handler

3. Pick the Service

  • HTTP API: simple, low-cost APIs
  • SQS: buffer work
  • SNS: fan out
  • EventBridge: route and schedule

4. Interview Point: Order Flow

  • Flow: API Gateway → Lambda → SNS → SQS queues → workers
  • Spikes: SQS buffer plus reserved concurrency
  • Duplicates: visibility timeout 6x function timeout, idempotent handler
  • Poison: DLQ with maxReceiveCount
AWSPage 7

Check yourself

A function has a 15 min timeout behind a default REST API. A job takes 40 s. What does the caller see?
  • A 504 at 29 s: the API Gateway integration timeout, not the function timeout
  • Fix: return 202 and queue the work (SQS)
Spot the bug: a function triggered by S3 uploads writes its output into the same bucket.
  • Each output fires the function again: a recursive loop and runaway cost
  • Fix: separate bucket or prefix filter, reserved concurrency, billing alarm
A proxy handler returns {"statusCode":200,"body":{"ok":true}}. Why does the client get a 502?
  • In proxy integration body must be a string, so a dict is a malformed response
  • Fix: json.dumps the body