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
问题严重程度解决方案
问题## 测量初始化阶段耗时
问题## 设置合适的超时时间
问题## 增加内存分配
问题## 验证VPC配置
问题## 告知Lambda无需等待事件循环清空
问题## 针对大文件上传
问题## 使用不同的存储桶/前缀