mcpField
A
aws-serverless

aws-serverless

github.com/davila7クラウド・DevOps33.0k334 回インストール1 日前に更新
リポジトリ

aws-serverless について

AWS サーバーレスアプリケーションを構築する開発者向けのパターンガイドです。Lambda ハンドラー、API Gateway 連携、再試行や DLQ を含む SQS 非同期処理を扱います。

主な機能

  1. 01Lambda ハンドラーの構成とエラー処理
  2. 02API Gateway 連携パターン
  3. 03SQS トリガーによる非同期処理
  4. 04バッチ失敗の報告と再試行
  5. 05デッドレターキューの設定

活用シーン

  1. 01Lambda API ハンドラーの実装
  2. 02Lambda による REST/HTTP エンドポイントの構築
  3. 03再試行と DLQ を使った SQS メッセージ処理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davila7/claude-code-templates --skill aws-serverless

インストール後、Claude Code で/aws-serverlessを入力して読み込まれたか確認します。

詳細

AWS Serverless

パターン

Lambda ハンドラーパターン

エラー処理を備えた適切な Lambda 関数の構造

使用する場面: ['Lambda 関数を実装するすべての場合', 'API ハンドラー、イベントプロセッサー、スケジュールタスク']

```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 Lambda Handler
# handler.py

import json
import os
import logging
import boto3
from 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 i
API Gateway 統合パターン

Lambda と連携する REST API および HTTP API の統合

使用する場面: ['Lambda を基盤とする REST API を構築する場合', '関数に HTTP エンドポイントが必要な場合']

```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"
// 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 =
イベント駆動 SQS パターン

信頼性の高い非同期処理のために SQS でトリガーされる Lambda

使用する場面: ['疎結合で非同期の処理が必要な場合', 'リトライロジックと DLQ が必要な場合', 'メッセージをバッチで処理する場合']

```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
// 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 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

アンチパターン

❌ モノリシックな Lambda

問題点: デプロイパッケージが大きいと、コールドスタートが遅くなります。 個々の処理を個別にスケールさせることが困難です。 更新がシステム全体に影響します。

❌ 大きな依存関係

問題点: デプロイパッケージのサイズが増加します。 コールドスタートが大幅に遅くなります。 SDK やライブラリの大部分が使われていない場合があります。

❌ VPC 内での同期呼び出し

問題点: VPC にアタッチされた Lambda では ENI のセットアップに余分なオーバーヘッドが発生します。 ブロッキングする DNS 参照や接続は、コールドスタートをさらに悪化させます。

⚠️ 注意すべきポイント

問題重大度解決策
問題高## INIT フェーズを計測する
問題高## 適切なタイムアウトを設定する
問題高## メモリ割り当てを増やす
問題中## VPC 構成を確認する
問題中## Lambda にイベントループの完了を待たないよう指示する
問題中## 大きなファイルをアップロードする場合
問題高## バケットやプレフィックスを分ける

コメント