Working with AWS Lambda
Relevant source files
The following files were used as context for generating this wiki page:- packages/@aws-cdk/aws-lambda/README.md
- packages/@aws-cdk/aws-lambda-nodejs/README.md
- packages/@aws-cdk/aws-lambda-python/README.md
- packages/@aws-cdk/aws-lambda-event-sources/README.md
- packages/@aws-cdk/aws-lambda-go/README.md
- packages/@aws-cdk/custom-resources/README.md
- packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.ts
- packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts
The AWS Cloud Development Kit (CDK) provides a comprehensive construct library for defining and configuring AWS Lambda functions. The primary module, @aws-cdk/aws-lambda, allows for the creation of Function constructs, while specialized modules like @aws-cdk/aws-lambda-nodejs, @aws-cdk/aws-lambda-python, and @aws-cdk/aws-lambda-go offer higher-level abstractions tailored for specific runtimes. These libraries simplify tasks such as code bundling, dependency management, and permissions.
This document outlines how to define Lambda functions, manage their code and dependencies, configure execution roles, set up event sources, and utilize advanced features like versioning, layers, and custom resource providers. The goal is to provide a developer-centric approach to defining serverless applications using infrastructure-as-code.
Sources: packages/@aws-cdk/aws-lambda/README.md:9-12, packages/@aws-cdk/aws-lambda/README.md:330-334
Defining a Function
The core of the library is the Function construct. A basic function requires a runtime, a handler location, and the code itself.
import { Function, Runtime, Code } from '@aws-cdk/aws-lambda';
import * as path from 'path';
const fn = new Function(this, 'MyFunction', {
runtime: Runtime.NODEJS_12_X,
handler: 'index.handler',
code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
});
Sources: packages/@aws-cdk/aws-lambda/README.md:14-18
Handler Code Sources
The lambda.Code class provides several static methods to specify the source of the function's code. This allows for flexibility in how the code is packaged and deployed.
The diagram below illustrates the different sources available through the lambda.Code class.
| Method | Description |
|---|---|
Code.fromAsset(path) | Specifies a local directory or .zip file. The CDK zips and uploads it to an S3 bucket before deployment. |
Code.fromBucket(bucket, key, version) | Specifies an S3 object containing the code archive. |
Code.fromInline(code) | Inlines the handler code as a string directly in the CloudFormation template. Limited to 4KiB. |
Code.fromDockerBuild(path, options) | Uses the result of a Docker build. The code is expected at /asset in the image, which is then zipped and uploaded to S3. |
Sources: packages/@aws-cdk/aws-lambda/README.md:25-33
Docker Image Support
Lambda functions can also be packaged as Docker images. The DockerImageFunction construct uses code from a Docker image asset or an existing ECR repository.
// From a local Dockerfile
new DockerImageFunction(this, 'AssetFunction', {
code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-handler')),
});
// From an existing ECR repository
import * as ecr from '@aws-cdk/aws-ecr';
const repo = new ecr.Repository(this, 'Repository');
new DockerImageFunction(this, 'ECRFunction', {
code: DockerImageCode.fromEcr(repo),
});
Sources: packages/@aws-cdk/aws-lambda/README.md:50-63
Language-Specific Constructs
To simplify development for specific languages, the CDK provides high-level constructs that automate transpiling, bundling, and dependency management.
NodejsFunction
The NodejsFunction construct in @aws-cdk/aws-lambda-nodejs is designed for TypeScript and JavaScript. It uses esbuild to transpile and bundle code, creating a minimal package with only necessary dependencies.
Features:
- Automatic entry file resolution based on construct ID.
- Dependency bundling from
package.json. - Support for external modules and
node_modulesinclusion for native dependencies. - Local bundling if
esbuildis installed, with a fallback to a Docker container.
The following diagram shows the bundling logic for NodejsFunction.
import { NodejsFunction } from '@aws-cdk/aws-lambda-nodejs';
// Automatically finds 'my-construct.api.ts'
const apiHandler = new NodejsFunction(this, 'api');
// With explicit entry
new NodejsFunction(this, 'MyFunction', {
entry: '/path/to/my/file.ts',
handler: 'myExportedFunc',
bundling: {
minify: true,
externalModules: ['aws-sdk'],
},
});
Sources: packages/@aws-cdk/aws-lambda-nodejs/README.md:26-34, packages/@aws-cdk/aws-lambda-nodejs/README.md:80-87
PythonFunction
The PythonFunction construct in @aws-cdk/aws-lambda-python handles dependency installation for Python runtimes. It automatically detects requirements.txt, Pipfile, or pyproject.toml (for Poetry) and installs dependencies in a Lambda-compatible Docker container.
import { PythonFunction } from "@aws-cdk/aws-lambda-python";
import * as lambda from "@aws-cdk/aws-lambda";
new PythonFunction(this, 'MyFunction', {
entry: '/path/to/my/function', // required
runtime: lambda.Runtime.PYTHON_3_6,
});
Sources: packages/@aws-cdk/aws-lambda-python/README.md:22-29
GoFunction
The GoFunction construct in @aws-cdk/aws-lambda-go compiles Go applications for the Lambda environment. It supports Go modules and can handle vendored dependencies. Bundling occurs locally if Go is installed, otherwise it falls back to Docker.
import { GoFunction } from '@aws-cdk/aws-lambda-go';
new GoFunction(this, 'handler', {
entry: 'app/cmd/api'
});
Sources: packages/@aws-cdk/aws-lambda-go/README.md:22-25
Execution and Permissions
Execution Role
Every Lambda function has an IAM Role. By default, the CDK creates one automatically with basic execution permissions (AWSLambdaBasicExecutionRole). This role can be accessed via the fn.role property. You can also provide a custom role.
import * as iam from '@aws-cdk/aws-iam';
const myRole = new iam.Role(this, 'My Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
// Add necessary permissions to the custom role
myRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole"));
const fn = new Function(this, 'MyFunction', {
// ...
role: myRole,
});
Sources: packages/@aws-cdk/aws-lambda/README.md:76-87
Resource-based Policies
To grant other AWS services or accounts permission to invoke a function, you can use resource-based policies. The grantInvoke() method is a convenient way to add the necessary permissions.
import * as iam from '@aws-cdk/aws-iam';
const principal = new iam.ServicePrincipal('my-service');
// Grant invocation permission to 'my-service'
fn.grantInvoke(principal);
// This is equivalent to:
fn.addPermission('my-service Invocation', {
principal: principal,
});
Sources: packages/@aws-cdk/aws-lambda/README.md:95-102
Versioning and Aliases
Lambda versions allow you to manage deployments by creating immutable snapshots of your function's code and configuration. An alias is a pointer to a specific version.
The fn.currentVersion property creates a new version whenever the function's code or configuration changes. An alias can then be pointed to this version.
This diagram shows how an alias points to a specific function version, while $LATEST points to the current draft.
import * as cdk from '@aws-cdk/core';
const fn = new Function(this, 'MyFunction', {
currentVersionOptions: {
removalPolicy: cdk.RemovalPolicy.RETAIN, // Retain old versions
},
// ...
});
// Create an alias 'live' that points to the current version
fn.currentVersion.addAlias('live');
Sources: packages/@aws-cdk/aws-lambda/README.md:168-177
Event Sources
Lambda functions can be triggered by a wide variety of event sources. The @aws-cdk/aws-lambda-event-sources module provides classes for configuring these triggers. The function.addEventSource() method is used to connect a function to a source.
This sequence diagram shows a Kinesis stream publishing records, which triggers an event source mapping that invokes a Lambda function.
Common Event Sources
| Source Class | Service | Example Usage |
|---|---|---|
SqsEventSource | Amazon SQS | fn.addEventSource(new SqsEventSource(queue)); |
S3EventSource | Amazon S3 | fn.addEventSource(new S3EventSource(bucket, { events: [s3.EventType.OBJECT_CREATED] })); |
DynamoEventSource | DynamoDB Streams | fn.addEventSource(new DynamoEventSource(table, { startingPosition: lambda.StartingPosition.LATEST })); |
KinesisEventSource | Kinesis Data Streams | fn.addEventSource(new KinesisEventSource(stream, { batchSize: 100, startingPosition: lambda.StartingPosition.TRIM_HORIZON })); |
SnsEventSource | Amazon SNS | fn.addEventSource(new SnsEventSource(topic)); |
Sources: packages/@aws-cdk/aws-lambda-event-sources/README.md
Advanced Configuration
Dead-Letter Queues (DLQ)
For asynchronous invocations, a Dead-Letter Queue (DLQ) can be configured to capture events that fail processing. You can enable it to have a queue created automatically or provide an existing SQS queue.
// Enable and auto-create a DLQ
new Function(this, 'MyFunction', {
// ...
deadLetterQueueEnabled: true
});
// Provide an existing SQS queue as a DLQ
import * as sqs from '@aws-cdk/aws-sqs';
const dlq = new sqs.Queue(this, 'DLQ');
new Function(this, 'MyFunction', {
// ...
deadLetterQueue: dlq
});
Sources: packages/@aws-cdk/aws-lambda/README.md:231-245
Tracing and Monitoring
-
AWS X-Ray: Enable active tracing to analyze and debug your function.
new Function(this, 'MyFunction', { // ... tracing: Tracing.ACTIVE }); -
CloudWatch Lambda Insights: Provides low-level runtime performance metrics.
new Function(this, 'MyFunction', { // ... insightsVersion: lambda.LambdaInsightsVersion.VERSION_1_0_98_0 });
Concurrency and Auto-Scaling
You can reserve a specific number of concurrent executions for a function or configure auto-scaling on an alias to manage provisioned concurrency based on utilization or a schedule.
// Reserved Concurrent Executions
new Function(this, 'MyFunction', {
// ...
reservedConcurrentExecutions: 100
});
// Auto-scaling on an alias
const alias = fn.currentVersion.addAlias('live');
const as = alias.addAutoScaling({ maxCapacity: 50 });
as.scaleOnUtilization({
utilizationTarget: 0.5,
});
Sources: packages/@aws-cdk/aws-lambda/README.md:265-269, packages/@aws-cdk/aws-lambda/README.md:275-283
Custom Resource Providers
The @aws-cdk/custom-resources module provides a framework for implementing CloudFormation custom resources using Lambda functions. This is useful for extending CloudFormation's capabilities. The Provider construct manages the lifecycle of the custom resource handler.
import * as cr from '@aws-cdk/custom-resources';
const onEvent = new lambda.Function(this, 'MyHandler', { /* ... */ });
const myProvider = new cr.Provider(this, 'MyProvider', {
onEventHandler: onEvent,
});
new CustomResource(this, 'Resource1', { serviceToken: myProvider.serviceToken });
Sources: packages/@aws-cdk/custom-resources/README.md:23-34
Summary
The AWS CDK offers a powerful and flexible way to work with AWS Lambda. The core aws-lambda library provides fundamental building blocks, while language-specific packages like aws-lambda-nodejs streamline the development workflow by handling bundling and dependencies automatically. With integrated support for event sources, versioning, monitoring, and advanced configurations, developers can define, deploy, and manage complex serverless applications entirely within their preferred programming language, leveraging the full power of infrastructure-as-code.
Sources: README.md:13-17, packages/@aws-cdk/aws-lambda/README.md:9-12