AWS Lambda

サーバーレスAWSFaaSイベント駆動自動スケーリングマイクロサービス

プラットフォーム

AWS Lambda

概要

AWS Lambdaは、Amazonが提供するサーバーレスコンピューティングサービスの先駆者として、イベント駆動型のコード実行、自動スケーリング、従量課金により、サーバー管理不要でアプリケーションを構築できる革新的なプラットフォームです。2014年のリリース以来、サーバーレス市場のリーダーシップを維持し、API Gateway、DynamoDB、S3、EventBridge等との深い統合により、完全サーバーレスアーキテクチャの構築を可能にしています。Node.js、Python、Java、C#、Go、Ruby、PowerShellなど15以上のランタイムをサポートし、ミリ秒単位の課金により、真の使用分のみの支払いを実現しています。

詳細

AWS Lambda 2025年版は、エンタープライズグレードのサーバーレスコンピューティングプラットフォームとして、毎日数十億回の実行をサポートしています。最新のArm Graviton3プロセッサーにより最大34%のパフォーマンス向上を実現し、プロビジョニング済み同時実行により一貫したレスポンス時間を保証します。Lambda Layersによる依存関係の管理、Lambda Extensionsによる観測性とセキュリティツールの統合、コンテナイメージサポートによる既存ワークロードの移行など、エンタープライズ要件に対応した豊富な機能を提供します。また、Lambda Snapstartにより、Javaアプリケーションの起動時間を最大90%短縮し、高性能な実行環境を実現しています。

主な特徴

  • イベント駆動実行: 250以上のAWSサービスとの統合
  • 自動スケーリング: ゼロから1000同時実行まで自動対応
  • 多言語ランタイム: 15以上のプログラミング言語サポート
  • 従量課金: 100ms単位の実行時間のみ課金
  • 高可用性: 99.95%のSLAと複数AZ冗長
  • セキュリティ: VPCサポート、IAM統合、暗号化

メリット・デメリット

メリット

  • サーバーレス市場のパイオニアとして最も成熟したエコシステム
  • 250以上のAWSサービスとのネイティブ統合による強力なイベント駆動アーキテクチャ
  • プロビジョニング済み同時実行による一貫したパフォーマンス保証
  • Lambda Snapstartによる大幅なコールドスタート時間短縮
  • 豊富なモニタリング・ログ機能(CloudWatch、X-Ray統合)
  • エンタープライズグレードのセキュリティとコンプライアンス対応

デメリット

  • 15分の実行時間制限により長時間処理には不適
  • 10GBのメモリ制限とEphemeral storageの制約
  • コールドスタートによる初回実行遅延(Snapstart対応言語以外)
  • AWSエコシステムへのベンダーロックインリスク
  • 複雑な権限管理(IAM)による学習コストの高さ
  • 大量同時実行時の課金額増大によるコスト予測困難性

参考ページ

書き方の例

セットアップと関数作成

# AWS CLIのインストールと設定
pip install awscli
aws configure

# AWS SAM CLIのインストール
pip install aws-sam-cli

# 新しいLambda関数プロジェクトの作成
sam init --runtime nodejs18.x --name my-lambda-function
cd my-lambda-function

# ローカルでの実行とテスト
sam local start-api --port 3000
sam local invoke HelloWorldFunction --event events/event.json
// Node.js関数の基本構造
exports.handler = async (event, context) => {
    console.log('Event:', JSON.stringify(event, null, 2));
    console.log('Context:', JSON.stringify(context, null, 2));
    
    try {
        // メイン処理
        const result = await processEvent(event);
        
        return {
            statusCode: 200,
            headers: {
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
            body: JSON.stringify({
                message: 'Function executed successfully',
                result: result,
                timestamp: new Date().toISOString()
            })
        };
    } catch (error) {
        console.error('Error:', error);
        
        return {
            statusCode: 500,
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                error: 'Internal server error',
                message: error.message
            })
        };
    }
};

async function processEvent(event) {
    // ビジネスロジックの実装
    return {
        eventType: event.Records ? 'S3/SQS Event' : 'API Gateway',
        eventSource: event.source || 'unknown',
        processed: true
    };
}

HTTP APIとリクエスト処理

// API Gateway統合のLambda関数
exports.apiHandler = async (event, context) => {
    const httpMethod = event.httpMethod || event.requestContext?.http?.method;
    const path = event.path || event.rawPath;
    const pathParameters = event.pathParameters || {};
    const queryParameters = event.queryStringParameters || {};
    const headers = event.headers || {};
    const body = event.body ? JSON.parse(event.body) : null;
    
    console.log(`${httpMethod} ${path}`);
    console.log('Path Parameters:', pathParameters);
    console.log('Query Parameters:', queryParameters);
    
    try {
        let response;
        
        switch (httpMethod) {
            case 'GET':
                response = await handleGet(pathParameters, queryParameters);
                break;
            case 'POST':
                response = await handlePost(body, headers);
                break;
            case 'PUT':
                response = await handlePut(pathParameters.id, body);
                break;
            case 'DELETE':
                response = await handleDelete(pathParameters.id);
                break;
            default:
                throw new Error(`Unsupported method: ${httpMethod}`);
        }
        
        return createApiResponse(200, response);
    } catch (error) {
        console.error('API Error:', error);
        return createApiResponse(500, { error: error.message });
    }
};

function createApiResponse(statusCode, body, headers = {}) {
    return {
        statusCode,
        headers: {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
            'Access-Control-Allow-Headers': 'Content-Type, Authorization',
            ...headers
        },
        body: JSON.stringify(body)
    };
}

async function handleGet(pathParams, queryParams) {
    if (pathParams.id) {
        return { message: `Getting item ${pathParams.id}` };
    }
    
    const limit = parseInt(queryParams.limit) || 10;
    const offset = parseInt(queryParams.offset) || 0;
    
    return {
        items: Array.from({ length: limit }, (_, i) => ({
            id: offset + i + 1,
            name: `Item ${offset + i + 1}`,
            created: new Date().toISOString()
        })),
        pagination: { limit, offset, total: 1000 }
    };
}

async function handlePost(body, headers) {
    const userAgent = headers['User-Agent'] || 'Unknown';
    const contentType = headers['Content-Type'] || 'application/json';
    
    return {
        message: 'Item created successfully',
        data: body,
        metadata: {
            userAgent,
            contentType,
            createdAt: new Date().toISOString()
        }
    };
}

データベース統合とデータ処理

// DynamoDB統合のLambda関数
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
const TABLE_NAME = process.env.TABLE_NAME || 'MyTable';

exports.databaseHandler = async (event, context) => {
    try {
        // S3イベントの処理例
        if (event.Records && event.Records[0].eventSource === 'aws:s3') {
            return await processS3Event(event.Records);
        }
        
        // SQSメッセージの処理例
        if (event.Records && event.Records[0].eventSource === 'aws:sqs') {
            return await processSQSMessages(event.Records);
        }
        
        // Direct DynamoDB操作
        return await processDatabaseOperation(event);
        
    } catch (error) {
        console.error('Database error:', error);
        throw error;
    }
};

async function processS3Event(records) {
    const results = [];
    
    for (const record of records) {
        const bucket = record.s3.bucket.name;
        const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));
        const eventName = record.eventName;
        
        console.log(`Processing S3 event: ${eventName} for ${bucket}/${key}`);
        
        const item = {
            id: `s3-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
            type: 'S3_EVENT',
            bucket: bucket,
            objectKey: key,
            eventName: eventName,
            timestamp: new Date().toISOString(),
            processed: true
        };
        
        // DynamoDBに記録
        await dynamodb.put({
            TableName: TABLE_NAME,
            Item: item
        }).promise();
        
        results.push(item);
    }
    
    return { processed: results.length, items: results };
}

async function processSQSMessages(records) {
    const batchResults = [];
    
    for (const record of records) {
        try {
            const messageBody = JSON.parse(record.body);
            const messageId = record.messageId;
            
            console.log(`Processing SQS message: ${messageId}`);
            
            // メッセージの処理とDynamoDBへの保存
            const processedItem = await processMessage(messageBody, messageId);
            batchResults.push(processedItem);
            
        } catch (error) {
            console.error(`Failed to process message ${record.messageId}:`, error);
            batchResults.push({ messageId: record.messageId, error: error.message });
        }
    }
    
    return { batchResults };
}

async function processMessage(messageBody, messageId) {
    const item = {
        id: messageId,
        type: 'SQS_MESSAGE',
        data: messageBody,
        processedAt: new Date().toISOString(),
        status: 'COMPLETED'
    };
    
    await dynamodb.put({
        TableName: TABLE_NAME,
        Item: item
    }).promise();
    
    return item;
}

async function processDatabaseOperation(event) {
    const operation = event.operation || 'query';
    
    switch (operation) {
        case 'query':
            return await queryItems(event.queryParams || {});
        case 'scan':
            return await scanTable(event.scanParams || {});
        case 'batchWrite':
            return await batchWriteItems(event.items || []);
        default:
            throw new Error(`Unsupported operation: ${operation}`);
    }
}

async function queryItems(params) {
    const queryParams = {
        TableName: TABLE_NAME,
        KeyConditionExpression: params.keyCondition || 'id = :id',
        ExpressionAttributeValues: params.attributeValues || { ':id': 'example' },
        Limit: params.limit || 10
    };
    
    const result = await dynamodb.query(queryParams).promise();
    return {
        items: result.Items,
        count: result.Count,
        lastEvaluatedKey: result.LastEvaluatedKey
    };
}

認証とセキュリティ

// Cognito JWT認証とLambda Authorizer
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
    jwksUri: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.USER_POOL_ID}/.well-known/jwks.json`
});

exports.authorizerHandler = async (event, context) => {
    try {
        const token = extractToken(event);
        const decodedToken = await verifyToken(token);
        const principalId = decodedToken.sub;
        
        // 認証成功 - IAMポリシーを生成
        const policy = generatePolicy(principalId, 'Allow', event.methodArn, decodedToken);
        console.log('Authorization successful for user:', principalId);
        
        return policy;
    } catch (error) {
        console.error('Authorization failed:', error);
        throw new Error('Unauthorized');
    }
};

function extractToken(event) {
    const authorizationHeader = event.headers?.Authorization || event.headers?.authorization;
    
    if (!authorizationHeader) {
        throw new Error('Missing Authorization header');
    }
    
    const tokenMatch = authorizationHeader.match(/^Bearer\s+(.+)$/);
    if (!tokenMatch) {
        throw new Error('Invalid Authorization header format');
    }
    
    return tokenMatch[1];
}

async function verifyToken(token) {
    const decodedHeader = jwt.decode(token, { complete: true });
    if (!decodedHeader || !decodedHeader.header.kid) {
        throw new Error('Invalid token header');
    }
    
    const signingKey = await getSigningKey(decodedHeader.header.kid);
    
    return jwt.verify(token, signingKey, {
        audience: process.env.CLIENT_ID,
        issuer: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.USER_POOL_ID}`,
        algorithms: ['RS256']
    });
}

function getSigningKey(kid) {
    return new Promise((resolve, reject) => {
        client.getSigningKey(kid, (err, key) => {
            if (err) {
                reject(err);
            } else {
                resolve(key.getPublicKey());
            }
        });
    });
}

function generatePolicy(principalId, effect, resource, decodedToken) {
    return {
        principalId,
        policyDocument: {
            Version: '2012-10-17',
            Statement: [
                {
                    Action: 'execute-api:Invoke',
                    Effect: effect,
                    Resource: resource
                }
            ]
        },
        context: {
            userId: principalId,
            email: decodedToken.email,
            groups: JSON.stringify(decodedToken['cognito:groups'] || []),
            tokenExpiry: decodedToken.exp.toString()
        }
    };
}

// セキュアなLambda関数の実装例
exports.secureHandler = async (event, context) => {
    // API Gateway Authorizerからのコンテキスト取得
    const userId = event.requestContext?.authorizer?.userId;
    const userEmail = event.requestContext?.authorizer?.email;
    const userGroups = JSON.parse(event.requestContext?.authorizer?.groups || '[]');
    
    if (!userId) {
        return createApiResponse(401, { error: 'Unauthorized' });
    }
    
    try {
        // リクエストの暗号化検証
        const encryptedData = event.body;
        const decryptedData = await decryptRequestData(encryptedData);
        
        // ユーザー権限の検証
        if (!hasRequiredPermissions(userGroups, 'READ_DATA')) {
            return createApiResponse(403, { error: 'Insufficient permissions' });
        }
        
        // セキュアなデータ処理
        const result = await processSecureData(decryptedData, userId);
        
        // レスポンスの暗号化
        const encryptedResponse = await encryptResponseData(result);
        
        return createApiResponse(200, { data: encryptedResponse });
        
    } catch (error) {
        console.error('Security error:', error);
        return createApiResponse(500, { error: 'Security validation failed' });
    }
};

async function decryptRequestData(encryptedData) {
    const AWS = require('aws-sdk');
    const kms = new AWS.KMS();
    
    const decryptParams = {
        CiphertextBlob: Buffer.from(encryptedData, 'base64')
    };
    
    const result = await kms.decrypt(decryptParams).promise();
    return JSON.parse(result.Plaintext.toString());
}

function hasRequiredPermissions(userGroups, requiredPermission) {
    const permissionMap = {
        'admin': ['READ_DATA', 'WRITE_DATA', 'DELETE_DATA'],
        'editor': ['READ_DATA', 'WRITE_DATA'],
        'viewer': ['READ_DATA']
    };
    
    return userGroups.some(group => 
        permissionMap[group]?.includes(requiredPermission)
    );
}

イベント駆動アーキテクチャ

// EventBridge統合のイベント処理
const AWS = require('aws-sdk');
const eventbridge = new AWS.EventBridge();
const sns = new AWS.SNS();

exports.eventDrivenHandler = async (event, context) => {
    try {
        // カスタムEventBridgeイベントの処理
        if (event.source && event['detail-type']) {
            return await processCustomEvent(event);
        }
        
        // CloudWatch Eventsからのスケジュール実行
        if (event.source === 'aws.events') {
            return await processScheduledEvent(event);
        }
        
        // Step Functions状態変更イベント
        if (event.source === 'aws.states') {
            return await processStepFunctionEvent(event);
        }
        
        return { message: 'Event processed successfully' };
        
    } catch (error) {
        console.error('Event processing error:', error);
        
        // エラー通知の送信
        await sendErrorNotification(error, event);
        throw error;
    }
};

async function processCustomEvent(event) {
    console.log('Processing custom event:', event['detail-type']);
    console.log('Event source:', event.source);
    console.log('Event detail:', JSON.stringify(event.detail, null, 2));
    
    const eventType = event['detail-type'];
    const eventData = event.detail;
    
    switch (eventType) {
        case 'User Registration':
            return await handleUserRegistration(eventData);
        case 'Order Placed':
            return await handleOrderPlaced(eventData);
        case 'Payment Processed':
            return await handlePaymentProcessed(eventData);
        default:
            console.log(`Unhandled event type: ${eventType}`);
            return { processed: false, reason: 'Unknown event type' };
    }
}

async function handleUserRegistration(userData) {
    console.log('New user registration:', userData.userId);
    
    // Welcome emailイベントの発行
    await publishEvent('user.welcome-email', {
        userId: userData.userId,
        email: userData.email,
        registrationTimestamp: new Date().toISOString()
    });
    
    // User profileイベントの発行
    await publishEvent('user.profile-setup', {
        userId: userData.userId,
        defaultSettings: {
            notifications: true,
            newsletter: false
        }
    });
    
    return { processed: true, eventType: 'User Registration' };
}

async function handleOrderPlaced(orderData) {
    console.log('New order placed:', orderData.orderId);
    
    // Inventory checkイベントの発行
    await publishEvent('inventory.check', {
        orderId: orderData.orderId,
        items: orderData.items,
        requestedBy: orderData.customerId
    });
    
    // Payment processingイベントの発行
    await publishEvent('payment.process', {
        orderId: orderData.orderId,
        amount: orderData.totalAmount,
        customerId: orderData.customerId,
        paymentMethod: orderData.paymentMethod
    });
    
    return { processed: true, eventType: 'Order Placed' };
}

async function publishEvent(eventType, eventData) {
    const params = {
        Entries: [
            {
                Source: 'my-application',
                DetailType: eventType,
                Detail: JSON.stringify(eventData),
                EventBusName: process.env.EVENT_BUS_NAME || 'default'
            }
        ]
    };
    
    const result = await eventbridge.putEvents(params).promise();
    console.log('Event published:', eventType, result.Entries[0].EventId);
}

async function processScheduledEvent(event) {
    console.log('Processing scheduled event');
    
    const ruleName = event.resources[0].split('/').pop();
    console.log('Triggered by rule:', ruleName);
    
    switch (ruleName) {
        case 'daily-backup':
            return await performDailyBackup();
        case 'weekly-report':
            return await generateWeeklyReport();
        case 'monthly-cleanup':
            return await performMonthlyCleanup();
        default:
            console.log(`Unknown scheduled rule: ${ruleName}`);
            return { processed: false };
    }
}

async function performDailyBackup() {
    console.log('Performing daily backup...');
    
    // データベースバックアップの実行
    const backupResult = await createDatabaseBackup();
    
    // バックアップ完了通知
    await publishEvent('backup.completed', {
        backupId: backupResult.backupId,
        timestamp: new Date().toISOString(),
        status: 'success'
    });
    
    return { 
        processed: true, 
        action: 'daily-backup',
        backupId: backupResult.backupId
    };
}

async function createDatabaseBackup() {
    // 実際のバックアップロジックを実装
    const backupId = `backup-${Date.now()}`;
    console.log('Creating backup:', backupId);
    
    // バックアップ処理をシミュレート
    return { backupId, status: 'completed' };
}

async function sendErrorNotification(error, originalEvent) {
    const message = {
        error: error.message,
        stack: error.stack,
        originalEvent: originalEvent,
        timestamp: new Date().toISOString(),
        functionName: process.env.AWS_LAMBDA_FUNCTION_NAME
    };
    
    const params = {
        TopicArn: process.env.ERROR_NOTIFICATION_TOPIC_ARN,
        Subject: 'Lambda Function Error Alert',
        Message: JSON.stringify(message, null, 2)
    };
    
    if (process.env.ERROR_NOTIFICATION_TOPIC_ARN) {
        await sns.publish(params).promise();
        console.log('Error notification sent');
    }
}

監視とパフォーマンス最適化

// CloudWatch Metrics & X-Ray統合の監視機能
const AWS = require('aws-sdk');
const AWSXRay = require('aws-xray-sdk-core');
const aws = AWSXRay.captureAWS(AWS);

const cloudwatch = new aws.CloudWatch();

exports.monitoringHandler = async (event, context) => {
    const segment = AWSXRay.getSegment();
    const subsegment = segment.addNewSubsegment('business-logic');
    
    try {
        // カスタムメトリクスの記録
        await recordCustomMetrics('FunctionInvocation', 1);
        
        // パフォーマンス測定の開始
        const startTime = Date.now();
        
        // メイン処理の実行
        const result = await performBusinessLogic(event);
        
        // 処理時間の記録
        const executionTime = Date.now() - startTime;
        await recordCustomMetrics('ExecutionTime', executionTime, 'Milliseconds');
        
        // 成功メトリクスの記録
        await recordCustomMetrics('SuccessfulExecution', 1);
        
        // X-Rayアノテーションの追加
        subsegment.addAnnotation('executionTime', executionTime);
        subsegment.addAnnotation('resultCount', result.items?.length || 0);
        subsegment.addMetadata('result', result);
        
        subsegment.close();
        
        return {
            statusCode: 200,
            body: JSON.stringify({
                result,
                metrics: {
                    executionTime,
                    timestamp: new Date().toISOString()
                }
            })
        };
        
    } catch (error) {
        // エラーメトリクスの記録
        await recordCustomMetrics('ErrorCount', 1);
        await recordCustomMetrics('ErrorRate', 1);
        
        // X-Rayエラー情報の追加
        subsegment.addError(error);
        subsegment.close(error);
        
        console.error('Function error:', error);
        throw error;
    }
};

async function recordCustomMetrics(metricName, value, unit = 'Count') {
    const params = {
        Namespace: 'MyApplication/Lambda',
        MetricData: [
            {
                MetricName: metricName,
                Value: value,
                Unit: unit,
                Timestamp: new Date(),
                Dimensions: [
                    {
                        Name: 'FunctionName',
                        Value: process.env.AWS_LAMBDA_FUNCTION_NAME
                    },
                    {
                        Name: 'Environment',
                        Value: process.env.ENVIRONMENT || 'production'
                    }
                ]
            }
        ]
    };
    
    try {
        await cloudwatch.putMetricData(params).promise();
    } catch (error) {
        console.error('Failed to record metric:', error);
    }
}

async function performBusinessLogic(event) {
    // X-Rayサブセグメントでの詳細トレーシング
    const subsegment = AWSXRay.getSegment().addNewSubsegment('data-processing');
    
    try {
        // データベースアクセスのトレーシング
        const dbSubsegment = subsegment.addNewSubsegment('database-query');
        const dbResults = await queryDatabase(event.query);
        dbSubsegment.addMetadata('queryResult', { count: dbResults.length });
        dbSubsegment.close();
        
        // 外部API呼び出しのトレーシング
        const apiSubsegment = subsegment.addNewSubsegment('external-api');
        const apiResults = await callExternalAPI(event.apiParams);
        apiSubsegment.addMetadata('apiResponse', apiResults);
        apiSubsegment.close();
        
        // データ処理のトレーシング
        const processSubsegment = subsegment.addNewSubsegment('data-transformation');
        const processedData = await processData(dbResults, apiResults);
        processSubsegment.addMetadata('processedItems', processedData.length);
        processSubsegment.close();
        
        subsegment.close();
        
        return {
            items: processedData,
            summary: {
                dbResultCount: dbResults.length,
                apiResultCount: apiResults.length,
                processedCount: processedData.length
            }
        };
        
    } catch (error) {
        subsegment.addError(error);
        subsegment.close(error);
        throw error;
    }
}

// パフォーマンス最適化の実装例
exports.optimizedHandler = async (event, context) => {
    // プロビジョニング済み同時実行での一貫性確保
    console.log('Function version:', context.functionVersion);
    console.log('Allocated memory:', context.memoryLimitInMB);
    
    // Lambda Layersからの依存関係使用
    const sharedUtils = require('/opt/nodejs/shared-utils');
    
    // 接続プールの再利用(コンテナの再利用時)
    if (!global.dbConnectionPool) {
        global.dbConnectionPool = await createDatabasePool();
        console.log('Database connection pool created');
    }
    
    // 環境変数キャッシュの活用
    const config = {
        tableName: process.env.TABLE_NAME,
        region: process.env.AWS_REGION,
        maxRetries: parseInt(process.env.MAX_RETRIES) || 3
    };
    
    try {
        // 非同期処理の並列実行による最適化
        const [userData, configData, metricsData] = await Promise.all([
            fetchUserData(event.userId),
            fetchConfiguration(config.tableName),
            fetchMetrics(event.timeRange)
        ]);
        
        // CPUバウンドな処理の最適化
        const processedResult = await optimizedDataProcessing(userData, configData);
        
        // メモリ使用量の監視
        const memoryUsage = process.memoryUsage();
        console.log('Memory usage:', {
            heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024) + ' MB',
            heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024) + ' MB'
        });
        
        return {
            statusCode: 200,
            body: JSON.stringify({
                result: processedResult,
                performance: {
                    memoryUsage: memoryUsage,
                    timestamp: new Date().toISOString()
                }
            })
        };
        
    } catch (error) {
        console.error('Optimized handler error:', error);
        throw error;
    }
};

async function createDatabasePool() {
    // データベース接続プールの作成(コンテナレベルでの再利用)
    const pool = {
        connections: new Map(),
        maxConnections: 10,
        created: new Date().toISOString()
    };
    
    console.log('Database pool initialized');
    return pool;
}

async function optimizedDataProcessing(userData, configData) {
    // ストリーミング処理による大量データの効率的処理
    const results = [];
    const batchSize = 100;
    
    for (let i = 0; i < userData.length; i += batchSize) {
        const batch = userData.slice(i, i + batchSize);
        const batchResults = await processBatch(batch, configData);
        results.push(...batchResults);
        
        // ガベージコレクションの促進
        if (i % 500 === 0) {
            global.gc && global.gc();
        }
    }
    
    return results;
}

async function processBatch(batch, config) {
    return batch.map(item => ({
        id: item.id,
        processed: true,
        timestamp: new Date().toISOString(),
        config: config.version
    }));
}

デプロイメントと本番運用

# SAM Template (template.yaml)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'AWS Lambda サーバーレスアプリケーション'

Globals:
  Function:
    Timeout: 30
    MemorySize: 1024
    Runtime: nodejs18.x
    Environment:
      Variables:
        ENVIRONMENT: !Ref Environment
        LOG_LEVEL: !Ref LogLevel

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues: [dev, staging, prod]
  LogLevel:
    Type: String
    Default: INFO
    AllowedValues: [DEBUG, INFO, WARN, ERROR]

Resources:
  # Lambda関数の定義
  MyLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub 'my-lambda-${Environment}'
      CodeUri: src/
      Handler: index.handler
      Runtime: nodejs18.x
      MemorySize: 1024
      Timeout: 30
      ReservedConcurrencyLimit: 100
      ProvisionedConcurrencyConfig:
        ProvisionedConcurrencyScaling:
          ProvisionedConcurrencyManagement: Manual
          ProvisionedConcurrencyCount: 10
      Environment:
        Variables:
          TABLE_NAME: !Ref DynamoDBTable
          BUCKET_NAME: !Ref S3Bucket
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /api/{proxy+}
            Method: any
            RestApiId: !Ref MyApi
        ScheduleEvent:
          Type: Schedule
          Properties:
            Schedule: 'rate(5 minutes)'
            Input: '{"source": "scheduled"}'
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref DynamoDBTable
        - S3ReadPolicy:
            BucketName: !Ref S3Bucket
        - CloudWatchPutMetricPolicy: {}

  # API Gateway
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Sub 'my-api-${Environment}'
      StageName: !Ref Environment
      TracingEnabled: true
      Cors:
        AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
        AllowOrigin: "'*'"
      Auth:
        DefaultAuthorizer: CognitoAuthorizer
        Authorizers:
          CognitoAuthorizer:
            UserPoolArn: !GetAtt CognitoUserPool.Arn

  # DynamoDB Table
  DynamoDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: !Sub 'my-table-${Environment}'
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      StreamSpecification:
        StreamViewType: NEW_AND_OLD_IMAGES
      PointInTimeRecoverySpecification:
        PointInTimeRecoveryEnabled: true

  # S3 Bucket
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'my-bucket-${Environment}-${AWS::AccountId}'
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  # Cognito User Pool
  CognitoUserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: !Sub 'my-pool-${Environment}'
      AutoVerifiedAttributes:
        - email
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireUppercase: true
          RequireLowercase: true
          RequireNumbers: true
          RequireSymbols: true

Outputs:
  ApiEndpoint:
    Description: 'API Gateway endpoint URL'
    Value: !Sub 'https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/${Environment}'
  FunctionName:
    Description: 'Lambda Function Name'
    Value: !Ref MyLambdaFunction
  TableName:
    Description: 'DynamoDB Table Name'
    Value: !Ref DynamoDBTable
#!/bin/bash
# deploy.sh - デプロイメントスクリプト

set -e

ENVIRONMENT=${1:-dev}
REGION=${2:-us-east-1}
STACK_NAME="my-lambda-app-${ENVIRONMENT}"

echo "Deploying to environment: ${ENVIRONMENT}"
echo "Region: ${REGION}"
echo "Stack name: ${STACK_NAME}"

# SAMビルド
echo "Building SAM application..."
sam build --use-container

# SAMデプロイ
echo "Deploying SAM application..."
sam deploy \
    --stack-name ${STACK_NAME} \
    --region ${REGION} \
    --capabilities CAPABILITY_IAM \
    --parameter-overrides \
        Environment=${ENVIRONMENT} \
        LogLevel=INFO \
    --confirm-changeset \
    --resolve-s3

# CloudFormationスタックの出力を取得
echo "Getting stack outputs..."
aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME} \
    --region ${REGION} \
    --query 'Stacks[0].Outputs'

# 関数の動作確認
echo "Testing deployed function..."
FUNCTION_NAME=$(aws cloudformation describe-stacks \
    --stack-name ${STACK_NAME} \
    --region ${REGION} \
    --query 'Stacks[0].Outputs[?OutputKey==`FunctionName`].OutputValue' \
    --output text)

aws lambda invoke \
    --function-name ${FUNCTION_NAME} \
    --region ${REGION} \
    --payload '{"test": true}' \
    response.json

echo "Deployment completed successfully!"
echo "Function response:"
cat response.json
# monitoring.sh - 監視とログ確認
#!/bin/bash

FUNCTION_NAME=${1:-my-lambda-function}
ENVIRONMENT=${2:-dev}

echo "Monitoring Lambda function: ${FUNCTION_NAME}"

# CloudWatch Logsの確認
echo "Fetching recent logs..."
aws logs describe-log-groups \
    --log-group-name-prefix "/aws/lambda/${FUNCTION_NAME}" \
    --query 'logGroups[0].logGroupName' \
    --output text | \
xargs -I {} aws logs tail {} --follow

# CloudWatch Metricsの確認
echo "Fetching metrics..."
aws cloudwatch get-metric-statistics \
    --namespace AWS/Lambda \
    --metric-name Duration \
    --dimensions Name=FunctionName,Value=${FUNCTION_NAME} \
    --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
    --end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
    --period 300 \
    --statistics Average,Maximum

# 関数の設定確認
echo "Function configuration:"
aws lambda get-function-configuration \
    --function-name ${FUNCTION_NAME} \
    --query '{
        Runtime: Runtime,
        MemorySize: MemorySize,
        Timeout: Timeout,
        LastModified: LastModified,
        Version: Version
    }'

echo "Monitoring complete!"