Post

AWS Lambda — Serverless Functions, Triggers, and Execution Model

A full walkthrough of AWS Lambda — runtimes, triggers, execution environment, concurrency, VPC integration, layers, and real-world serverless patterns

AWS Lambda — Serverless Functions, Triggers, and Execution Model

What is Lambda?

AWS Lambda is a serverless compute service. You upload your code and Lambda runs it — no servers to provision, no OS to patch, no capacity to manage. Lambda executes your function in response to events and automatically scales from zero to thousands of concurrent executions.

You pay only for the time your function runs — billed in 1ms increments. If nobody calls your function, you pay nothing.


Core Concepts

TermMeaning
FunctionYour code + configuration (runtime, memory, timeout, environment variables)
HandlerThe entry point — the specific function Lambda calls when triggered
EventThe JSON payload passed to your function by the trigger
ContextMetadata about the invocation (request ID, remaining time, function name)
Execution environmentThe isolated runtime sandbox Lambda uses to run your function
TriggerThe event source that invokes your function
LayerA zip archive of libraries or dependencies shared across functions

Supported Runtimes

RuntimeVersions
Python3.9, 3.10, 3.11, 3.12
Node.js18.x, 20.x
Java8, 11, 17, 21
Go1.x (provided.al2023)
.NET6, 8
Ruby3.2
Custom runtimeAny language via bootstrap binary on Amazon Linux 2023

Function Configuration

📸 SCREENSHOT: Lambda → Functions → Create Function. Show the runtime dropdown, handler field (e.g. index.handler), and the architecture selection (x86_64 / arm64).

Memory and Timeout

Memory: 128 MB to 10,240 MB (in 1 MB increments). CPU is allocated proportionally to memory — more memory = more CPU. Timeout: 1 second to 15 minutes maximum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Create a Lambda function
aws lambda create-function \
  --function-name my-processor \
  --runtime python3.12 \
  --handler lambda_function.lambda_handler \
  --role arn:aws:iam::123456789012:role/lambda-execution-role \
  --zip-file fileb://function.zip \
  --memory-size 512 \
  --timeout 30 \
  --environment Variables='{DB_HOST=db.internal,LOG_LEVEL=INFO}'

# Update function code
aws lambda update-function-code \
  --function-name my-processor \
  --zip-file fileb://function.zip

# Update configuration
aws lambda update-function-configuration \
  --function-name my-processor \
  --memory-size 1024 \
  --timeout 60

Handler Structure

Python example:

1
2
3
4
5
6
7
8
9
10
11
import json

def lambda_handler(event, context):
    print(f"Event: {json.dumps(event)}")
    print(f"Request ID: {context.aws_request_id}")
    print(f"Remaining time: {context.get_remaining_time_in_millis()}ms")

    return {
        'statusCode': 200,
        'body': json.dumps({'message': 'OK'})
    }

Node.js example:

1
2
3
4
5
6
7
exports.handler = async (event, context) => {
    console.log('Event:', JSON.stringify(event));
    return {
        statusCode: 200,
        body: JSON.stringify({ message: 'OK' })
    };
};

Triggers and Event Sources

Lambda functions are invoked by triggers. Each trigger type passes a different event structure.

API Gateway / ALB

The most common pattern — HTTP request triggers a Lambda function. API Gateway passes the full request (method, path, headers, body) as JSON.

📸 SCREENSHOT: Lambda → Function → Configuration → Triggers → Add Trigger. Show the API Gateway trigger selected, and the HTTP API created with an open endpoint.

1
Client → API Gateway → Lambda → response

S3 Events

Lambda triggered when objects are created, deleted, or modified in an S3 bucket. Use for image resizing, document processing, ETL pipelines.

1
2
3
4
5
6
7
8
{
  "Records": [{
    "s3": {
      "bucket": {"name": "my-uploads"},
      "object": {"key": "images/photo.jpg", "size": 1024}
    }
  }]
}

SQS

Lambda polls an SQS queue and processes messages in batches. Lambda scales out consumers automatically. Failed messages go back to the queue (or DLQ after max retries).

1
2
3
4
5
6
# Add SQS trigger
aws lambda create-event-source-mapping \
  --function-name my-processor \
  --event-source-arn arn:aws:sqs:eu-west-1:123456789012:my-queue \
  --batch-size 10 \
  --maximum-batching-window-in-seconds 5

EventBridge (Scheduled)

Run Lambda on a schedule — like cron in the cloud.

1
2
3
4
5
6
7
8
9
# Create a rule to run every 5 minutes
aws events put-rule \
  --name every-5-minutes \
  --schedule-expression "rate(5 minutes)"

# Add Lambda as the target
aws events put-targets \
  --rule every-5-minutes \
  --targets "Id=1,Arn=arn:aws:lambda:eu-west-1:123456789012:function:my-processor"

DynamoDB Streams and Kinesis

Lambda processes records from a stream in order. Used for change data capture, real-time analytics, event sourcing.

Common Trigger Summary

TriggerInvocation TypeRetry Behaviour
API Gateway / ALBSynchronousClient handles errors
S3AsynchronousLambda retries 2x, then DLQ
SQSEvent source mapping (poll)Visibility timeout, DLQ
SNSAsynchronousLambda retries 2x, then DLQ
DynamoDB StreamsEvent source mappingRetry until TTL or shards exhausted
EventBridgeAsynchronousLambda retries 2x, then DLQ
CognitoSynchronousNo retry — must return response

Invocation Types

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Synchronous — waits for response
aws lambda invoke \
  --function-name my-processor \
  --payload '{"key": "value"}' \
  --cli-binary-format raw-in-base64-out \
  response.json

# Asynchronous — fire and forget
aws lambda invoke \
  --function-name my-processor \
  --invocation-type Event \
  --payload '{"key": "value"}' \
  --cli-binary-format raw-in-base64-out \
  response.json

Execution Environment and Cold Starts

When Lambda receives a request, it:

  1. Provisions an execution environment (OS, runtime, your code)
  2. Runs your handler

If a warm environment is available (recent invocation), it reuses it — warm start, fast. If no warm environment exists, Lambda initialises a new one — cold start, adds 100ms–1000ms latency.

Cold Start Causes

  • Function hasn’t been called recently (environment recycled)
  • New deployment
  • Concurrency spike — Lambda needs new environments

Reducing Cold Starts

  • Provisioned Concurrency — pre-warm N execution environments, always ready
  • Smaller deployment packages (less to load)
  • Use arm64 architecture (Graviton2) — ~10-20% better performance and lower cost
  • Avoid VPC for functions that don’t need it (VPC adds ~1-2s cold start for ENI attachment)
1
2
3
4
5
# Configure provisioned concurrency
aws lambda put-provisioned-concurrency-config \
  --function-name my-processor \
  --qualifier prod \
  --provisioned-concurrent-executions 10

Concurrency

Concurrency is the number of function instances running simultaneously.

Concurrency TypeDescription
UnreservedShared pool across all functions in the account (default: 1000 per region)
ReservedGuaranteed concurrency for a specific function — takes from shared pool
ProvisionedPre-warmed environments — eliminates cold starts
1
2
3
4
# Reserve 100 concurrent executions for critical function
aws lambda put-function-concurrency \
  --function-name my-critical-function \
  --reserved-concurrent-executions 100

📸 SCREENSHOT: Lambda → Function → Configuration → Concurrency. Show the reserved concurrency field set to 100, and the note about removing from the account pool.


IAM Execution Role

Every Lambda function needs an execution role — an IAM role that defines what AWS services the function can call.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

Minimum permissions every Lambda needs: logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents. Without these, your function runs but you cannot see any logs.


Lambda Layers

A layer is a zip archive containing libraries, a custom runtime, or data files. Multiple functions can share the same layer — you package dependencies once and reference them from any function.

1
2
3
4
5
6
7
8
9
10
# Publish a layer
aws lambda publish-layer-version \
  --layer-name python-requests \
  --zip-file fileb://requests-layer.zip \
  --compatible-runtimes python3.11 python3.12

# Attach layer to a function
aws lambda update-function-configuration \
  --function-name my-processor \
  --layers arn:aws:lambda:eu-west-1:123456789012:layer:python-requests:3

Functions can use up to 5 layers simultaneously. Total unzipped size of function + layers must be under 250 MB.


VPC Integration

By default Lambda runs outside your VPC — it can reach the internet but not private resources (RDS, ElastiCache, internal services). You can attach Lambda to a VPC to give it access to private subnets.

Attaching to a VPC increases cold start time (Lambda must attach an ENI). Only put Lambda in a VPC when it actually needs to reach private resources.

1
2
3
aws lambda update-function-configuration \
  --function-name my-processor \
  --vpc-config SubnetIds=subnet-private-1a,subnet-private-1b,SecurityGroupIds=sg-lambda

When Lambda is in a VPC and needs internet access (to call external APIs), route its outbound traffic through a NAT Gateway — Lambda in a private subnet, NAT Gateway in a public subnet.


Destinations and Dead Letter Queues

For asynchronous invocations, you can configure:

  • On success destination — SNS, SQS, EventBridge, or another Lambda
  • On failure destination — same options
  • Dead Letter Queue (DLQ) — SQS or SNS for failed events after retries
1
2
3
4
5
6
7
aws lambda put-function-event-invoke-config \
  --function-name my-processor \
  --maximum-retry-attempts 1 \
  --destination-config '{
    "OnSuccess": {"Destination": "arn:aws:sqs:...:success-queue"},
    "OnFailure": {"Destination": "arn:aws:sqs:...:dlq"}
  }'

Monitoring and Observability

Lambda automatically sends metrics to CloudWatch:

  • Invocations, Errors, Throttles, Duration, ConcurrentExecutions

Lambda automatically sends logs to CloudWatch Logs — each print() or console.log() appears there.

Enable X-Ray tracing to see end-to-end latency across Lambda → downstream services.

1
2
3
4
# Enable X-Ray active tracing
aws lambda update-function-configuration \
  --function-name my-processor \
  --tracing-config Mode=Active

📸 SCREENSHOT: CloudWatch → Log Groups → /aws/lambda/my-processor. Show the log streams list, then click into one stream to show a cold start init log line followed by function output.


Pricing

Lambda pricing has two components:

ComponentPrice
Requests$0.20 per 1 million requests (first 1M/month free)
Duration$0.0000166667 per GB-second (first 400,000 GB-seconds/month free)

GB-seconds = memory allocated (in GB) × execution duration (in seconds).

Example: a 512 MB function running for 200ms = 0.5 GB × 0.2s = 0.1 GB-second. At 1 million invocations per day = ~100,000 GB-seconds/day — well within the free tier initially, then fractions of a cent.

arm64 (Graviton) functions are ~20% cheaper than x86_64.


Real-World Patterns

Pattern 1 — REST API backend

1
Client → API Gateway → Lambda → DynamoDB

Completely serverless API. Lambda handles each request, scales to zero when idle.

Pattern 2 — S3 event processing

1
Upload to S3 → S3 Event → Lambda → resize image → save to S3 output bucket

Image resizer, PDF processor, virus scanner.

Pattern 3 — Scheduled jobs

1
EventBridge rule (cron) → Lambda → clean up database / send report / sync data

Replaces traditional cron jobs on EC2.

Pattern 4 — SQS worker

1
Producer → SQS queue → Lambda (batch processor) → downstream service

Decoupled, scalable message processing. Lambda scales consumers automatically based on queue depth.


Quick Reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# List functions
aws lambda list-functions --output table

# Invoke a function
aws lambda invoke \
  --function-name my-processor \
  --payload '{}' \
  --cli-binary-format raw-in-base64-out \
  /tmp/response.json && cat /tmp/response.json

# View recent logs
aws logs tail /aws/lambda/my-processor --follow

# Get function configuration
aws lambda get-function-configuration --function-name my-processor

# List event source mappings (SQS/Kinesis/DynamoDB triggers)
aws lambda list-event-source-mappings --function-name my-processor

# Delete a function
aws lambda delete-function --function-name my-processor
This post is licensed under CC BY 4.0 by the author.