aws-serverless
AWS Serverless
Section titled “AWS Serverless”Patterns
Section titled “Patterns”Lambda Handler Pattern
Section titled “Lambda Handler Pattern”Proper Lambda function structure with error handling
When to use: [‘Any Lambda function implementation’, ‘API handlers, event processors, scheduled tasks’]
```javascript// Node.js Lambda Handler// 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 functionexports.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 Lambda Handlerimport jsonimport osimport loggingimport boto3from botocore.exceptions import ClientError
# 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 iAPI Gateway Integration Pattern
Section titled “API Gateway Integration Pattern”REST API and HTTP API integration with Lambda
When to use: [‘Building REST APIs backed by Lambda’, ‘Need HTTP endpoints for functions’]
```yaml# 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"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
Section titled “Event-Driven SQS Pattern”Lambda triggered by SQS for reliable async processing
When to use: [‘Decoupled, asynchronous processing’, ‘Need retry logic and DLQ’, ‘Processing messages in batches’]
```yamlResources: 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 daysexports.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 versionimport jsonimport 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_iteAnti-Patterns
Section titled “Anti-Patterns”❌ Monolithic Lambda
Section titled “❌ Monolithic Lambda”Why bad: Large deployment packages cause slow cold starts. Hard to scale individual operations. Updates affect entire system.
❌ Large Dependencies
Section titled “❌ Large Dependencies”Why bad: Increases deployment package size. Slows down cold starts significantly. Most of SDK/library may be unused.
❌ Synchronous Calls in VPC
Section titled “❌ Synchronous Calls in VPC”Why bad: VPC-attached Lambdas have ENI setup overhead. Blocking DNS lookups or connections worsen cold starts.
⚠️ Sharp Edges
Section titled “⚠️ Sharp Edges”| Issue | Severity | Solution |
|---|---|---|
| Issue | high | ## Measure your INIT phase |
| Issue | high | ## Set appropriate timeout |
| Issue | high | ## Increase memory allocation |
| Issue | medium | ## Verify VPC configuration |
| Issue | medium | ## Tell Lambda not to wait for event loop |
| Issue | medium | ## For large file uploads |
| Issue | high | ## Use different buckets/prefixes |
Gap Analysis Rule
Section titled “Gap Analysis Rule”Always identify gaps and suggest next steps to users. In case there is no gaps anymore, then AI should clearly state that there is no gap left.