aws-serverless

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AWS Serverless

AWS Serverless

Patterns

模式

Lambda Handler Pattern

Lambda处理器模式

Proper Lambda function structure with error handling
When to use: ['Any Lambda function implementation', 'API handlers, event processors, scheduled tasks']
python
```javascript
// Node.js Lambda Handler
// handler.js

// Initialize outside handler (reused across invocations)
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

// Handler function
exports.handler = async (event, context) => {
  // Optional: Don't wait for event loop to clear (Node.js)
  context.callbackWaitsForEmptyEventLoop = false;

  try {
    // Parse input based on event source
    const body = typeof event.body === 'string'
      ? JSON.parse(event.body)
      : event.body;

    // Business logic
    const result = await processRequest(body);

    // Return API Gateway compatible response
    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
      },
      body: JSON.stringify(result)
    };
  } catch (error) {
    console.error('Error:', JSON.stringify({
      error: error.message,
      stack: error.stack,
      requestId: context.awsRequestId
    }));

    return {
      statusCode: error.statusCode || 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        error: error.message || 'Internal server error'
      })
    };
  }
};

async function processRequest(data) {
  // Your business logic here
  const result = await docClient.send(new GetCommand({
    TableName: process.env.TABLE_NAME,
    Key: { id: data.id }
  }));
  return result.Item;
}
python
undefined
带错误处理的规范Lambda函数结构
适用场景: ['任意Lambda函数实现', 'API处理器、事件处理器、定时任务']
python
```javascript
// Node.js Lambda Handler
// handler.js

// Initialize outside handler (reused across invocations)
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

// Handler function
exports.handler = async (event, context) => {
  // Optional: Don't wait for event loop to clear (Node.js)
  context.callbackWaitsForEmptyEventLoop = false;

  try {
    // Parse input based on event source
    const body = typeof event.body === 'string'
      ? JSON.parse(event.body)
      : event.body;

    // Business logic
    const result = await processRequest(body);

    // Return API Gateway compatible response
    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*'
      },
      body: JSON.stringify(result)
    };
  } catch (error) {
    console.error('Error:', JSON.stringify({
      error: error.message,
      stack: error.stack,
      requestId: context.awsRequestId
    }));

    return {
      statusCode: error.statusCode || 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        error: error.message || 'Internal server error'
      })
    };
  }
};

async function processRequest(data) {
  // Your business logic here
  const result = await docClient.send(new GetCommand({
    TableName: process.env.TABLE_NAME,
    Key: { id: data.id }
  }));
  return result.Item;
}
python
undefined

Python Lambda Handler

Python Lambda Handler

handler.py

handler.py

import json import os import logging import boto3 from botocore.exceptions import ClientError
import json import os import logging import boto3 from botocore.exceptions import ClientError

Initialize outside handler (reused across invocations)

Initialize outside handler (reused across invocations)

logger = logging.getLogger() logger.setLevel(logging.INFO)
dynamodb = boto3.resource('dynamodb') table = dynamodb.Table(os.environ['TABLE_NAME'])
def handler(event, context): try: # Parse i
undefined
logger = logging.getLogger() logger.setLevel(logging.INFO)
dynamodb = boto3.resource('dynamodb') table = dynamodb.Table(os.environ['TABLE_NAME'])
def handler(event, context): try: # Parse i
undefined

API Gateway Integration Pattern

API Gateway集成模式

REST API and HTTP API integration with Lambda
When to use: ['Building REST APIs backed by Lambda', 'Need HTTP endpoints for functions']
javascript
```yaml
REST API和HTTP API与Lambda的集成方案
适用场景: ['构建基于Lambda的REST API', '需要为函数提供HTTP端点']
javascript
```yaml

template.yaml (SAM)

template.yaml (SAM)

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31
Globals: Function: Runtime: nodejs20.x Timeout: 30 MemorySize: 256 Environment: Variables: TABLE_NAME: !Ref ItemsTable
Resources:

HTTP API (recommended for simple use cases)

HttpApi: Type: AWS::Serverless::HttpApi Properties: StageName: prod CorsConfiguration: AllowOrigins: - "" AllowMethods: - GET - POST - DELETE AllowHeaders: - ""

Lambda Functions

GetItemFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/get.handler Events: GetItem: Type: HttpApi Properties: ApiId: !Ref HttpApi Path: /items/{id} Method: GET Policies: - DynamoDBReadPolicy: TableName: !Ref ItemsTable
CreateItemFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/create.handler Events: CreateItem: Type: HttpApi Properties: ApiId: !Ref HttpApi Path: /items Method: POST Policies: - DynamoDBCrudPolicy: TableName: !Ref ItemsTable

DynamoDB Table

ItemsTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH BillingMode: PAY_PER_REQUEST
Outputs: ApiUrl: Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/prod"

```javascript
// src/handlers/get.js
const { getItem } = require('../lib/dynamodb');

exports.handler = async (event) => {
  const id = event.pathParameters?.id;

  if (!id) {
    return {
      statusCode: 400,
      body: JSON.stringify({ error: 'Missing id parameter' })
    };
  }

  const item =
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31
Globals: Function: Runtime: nodejs20.x Timeout: 30 MemorySize: 256 Environment: Variables: TABLE_NAME: !Ref ItemsTable
Resources:

HTTP API (recommended for simple use cases)

HttpApi: Type: AWS::Serverless::HttpApi Properties: StageName: prod CorsConfiguration: AllowOrigins: - "" AllowMethods: - GET - POST - DELETE AllowHeaders: - ""

Lambda Functions

GetItemFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/get.handler Events: GetItem: Type: HttpApi Properties: ApiId: !Ref HttpApi Path: /items/{id} Method: GET Policies: - DynamoDBReadPolicy: TableName: !Ref ItemsTable
CreateItemFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/create.handler Events: CreateItem: Type: HttpApi Properties: ApiId: !Ref HttpApi Path: /items Method: POST Policies: - DynamoDBCrudPolicy: TableName: !Ref ItemsTable

DynamoDB Table

ItemsTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH BillingMode: PAY_PER_REQUEST
Outputs: ApiUrl: Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/prod"

```javascript
// src/handlers/get.js
const { getItem } = require('../lib/dynamodb');

exports.handler = async (event) => {
  const id = event.pathParameters?.id;

  if (!id) {
    return {
      statusCode: 400,
      body: JSON.stringify({ error: 'Missing id parameter' })
    };
  }

  const item =

Event-Driven SQS Pattern

事件驱动SQS模式

Lambda triggered by SQS for reliable async processing
When to use: ['Decoupled, asynchronous processing', 'Need retry logic and DLQ', 'Processing messages in batches']
python
```yaml
SQS触发Lambda实现可靠的异步处理
适用场景: ['解耦的异步处理场景', '需要重试逻辑和死信队列', '批量处理消息']
python
```yaml

template.yaml

template.yaml

Resources: ProcessorFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/processor.handler Events: SQSEvent: Type: SQS Properties: Queue: !GetAtt ProcessingQueue.Arn BatchSize: 10 FunctionResponseTypes: - ReportBatchItemFailures # Partial batch failure handling
ProcessingQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 180 # 6x Lambda timeout RedrivePolicy: deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn maxReceiveCount: 3
DeadLetterQueue: Type: AWS::SQS::Queue Properties: MessageRetentionPeriod: 1209600 # 14 days

```javascript
// src/handlers/processor.js
exports.handler = async (event) => {
  const batchItemFailures = [];

  for (const record of event.Records) {
    try {
      const body = JSON.parse(record.body);
      await processMessage(body);
    } catch (error) {
      console.error(`Failed to process message ${record.messageId}:`, error);
      // Report this item as failed (will be retried)
      batchItemFailures.push({
        itemIdentifier: record.messageId
      });
    }
  }

  // Return failed items for retry
  return { batchItemFailures };
};

async function processMessage(message) {
  // Your processing logic
  console.log('Processing:', message);

  // Simulate work
  await saveToDatabase(message);
}
python
undefined
Resources: ProcessorFunction: Type: AWS::Serverless::Function Properties: Handler: src/handlers/processor.handler Events: SQSEvent: Type: SQS Properties: Queue: !GetAtt ProcessingQueue.Arn BatchSize: 10 FunctionResponseTypes: - ReportBatchItemFailures # Partial batch failure handling
ProcessingQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 180 # 6x Lambda timeout RedrivePolicy: deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn maxReceiveCount: 3
DeadLetterQueue: Type: AWS::SQS::Queue Properties: MessageRetentionPeriod: 1209600 # 14 days

```javascript
// src/handlers/processor.js
exports.handler = async (event) => {
  const batchItemFailures = [];

  for (const record of event.Records) {
    try {
      const body = JSON.parse(record.body);
      await processMessage(body);
    } catch (error) {
      console.error(`Failed to process message ${record.messageId}:`, error);
      // Report this item as failed (will be retried)
      batchItemFailures.push({
        itemIdentifier: record.messageId
      });
    }
  }

  // Return failed items for retry
  return { batchItemFailures };
};

async function processMessage(message) {
  // Your processing logic
  console.log('Processing:', message);

  // Simulate work
  await saveToDatabase(message);
}
python
undefined

Python version

Python version

import json import logging
logger = logging.getLogger()
def handler(event, context): batch_item_failures = []
for record in event['Records']:
    try:
        body = json.loads(record['body'])
        process_message(body)
    except Exception as e:
        logger.error(f"Failed to process {record['messageId']}: {e}")
        batch_item_failures.append({
            'itemIdentifier': record['messageId']
        })

return {'batchItemFailures': batch_ite
undefined
import json import logging
logger = logging.getLogger()
def handler(event, context): batch_item_failures = []
for record in event['Records']:
    try:
        body = json.loads(record['body'])
        process_message(body)
    except Exception as e:
        logger.error(f"Failed to process {record['messageId']}: {e}")
        batch_item_failures.append({
            'itemIdentifier': record['messageId']
        })

return {'batchItemFailures': batch_ite
undefined

Anti-Patterns

反模式

❌ Monolithic Lambda

❌ 单体Lambda

Why bad: Large deployment packages cause slow cold starts. Hard to scale individual operations. Updates affect entire system.
弊端:部署包体积过大会导致冷启动缓慢,单个操作难以独立扩展,更新会影响整个系统。

❌ Large Dependencies

❌ 依赖体积过大

Why bad: Increases deployment package size. Slows down cold starts significantly. Most of SDK/library may be unused.
弊端:会增加部署包大小,大幅拖慢冷启动速度,SDK/库的大部分功能可能并未被使用。

❌ Synchronous Calls in VPC

❌ VPC内同步调用

Why bad: VPC-attached Lambdas have ENI setup overhead. Blocking DNS lookups or connections worsen cold starts.
弊端:挂载VPC的Lambda存在ENI设置开销,阻塞式DNS查询或连接会进一步恶化冷启动性能。

⚠️ Sharp Edges

⚠️ 注意事项

IssueSeveritySolution
Issuehigh## Measure your INIT phase
Issuehigh## Set appropriate timeout
Issuehigh## Increase memory allocation
Issuemedium## Verify VPC configuration
Issuemedium## Tell Lambda not to wait for event loop
Issuemedium## For large file uploads
Issuehigh## Use different buckets/prefixes
问题严重程度解决方案
问题## 测量INIT阶段耗时
问题## 设置合理的超时时间
问题## 增加内存分配
问题## 校验VPC配置
问题## 配置Lambda无需等待事件循环清空
问题## 大文件上传场景处理方案
问题## 使用不同的存储桶/前缀