[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-5ee212a6-6ef5-465d-80be-256caca83b08":3,"$fzgtQC1FUjygiRhgJ40R7ghSLgJALo6B9Jg8xjmJFNBk":42},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"5ee212a6-6ef5-465d-80be-256caca83b08","aws-serverless","构建生产就绪型无服务器架构的专业技能","cat_coding_backend","mod_coding","sickn33,coding","---\nname: aws-serverless\ndescription: Specialized skill for building production-ready serverless\n  applications on AWS. Covers Lambda functions, API Gateway, DynamoDB, SQS\u002FSNS\n  event-driven patterns, SAM\u002FCDK deployment, and cold start optimization.\nrisk: unknown\nsource: vibeship-spawner-skills (Apache 2.0)\ndate_added: 2026-02-27\n---\n\n# AWS Serverless\n\nSpecialized skill for building production-ready serverless applications on AWS.\nCovers Lambda functions, API Gateway, DynamoDB, SQS\u002FSNS event-driven patterns,\nSAM\u002FCDK deployment, and cold start optimization.\n\n## Principles\n\n- Right-size memory and timeout (measure before optimizing)\n- Minimize cold starts for latency-sensitive workloads\n- Use SnapStart for Java\u002F.NET functions\n- Prefer HTTP API over REST API for simple use cases\n- Design for failure with DLQs and retries\n- Keep deployment packages small\n- Use environment variables for configuration\n- Implement structured logging with correlation IDs\n\n## Patterns\n\n### Lambda Handler Pattern\n\nProper Lambda function structure with error handling\n\n**When to use**: Any Lambda function implementation,API handlers, event processors, scheduled tasks\n\n```javascript\n\u002F\u002F Node.js Lambda Handler\n\u002F\u002F handler.js\n\n\u002F\u002F Initialize outside handler (reused across invocations)\nconst { DynamoDBClient } = require('@aws-sdk\u002Fclient-dynamodb');\nconst { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk\u002Flib-dynamodb');\n\nconst client = new DynamoDBClient({});\nconst docClient = DynamoDBDocumentClient.from(client);\n\n\u002F\u002F Handler function\nexports.handler = async (event, context) => {\n  \u002F\u002F Optional: Don't wait for event loop to clear (Node.js)\n  context.callbackWaitsForEmptyEventLoop = false;\n\n  try {\n    \u002F\u002F Parse input based on event source\n    const body = typeof event.body === 'string'\n      ? JSON.parse(event.body)\n      : event.body;\n\n    \u002F\u002F Business logic\n    const result = await processRequest(body);\n\n    \u002F\u002F Return API Gateway compatible response\n    return {\n      statusCode: 200,\n      headers: {\n        'Content-Type': 'application\u002Fjson',\n        'Access-Control-Allow-Origin': '*'\n      },\n      body: JSON.stringify(result)\n    };\n  } catch (error) {\n    console.error('Error:', JSON.stringify({\n      error: error.message,\n      stack: error.stack,\n      requestId: context.awsRequestId\n    }));\n\n    return {\n      statusCode: error.statusCode || 500,\n      headers: { 'Content-Type': 'application\u002Fjson' },\n      body: JSON.stringify({\n        error: error.message || 'Internal server error'\n      })\n    };\n  }\n};\n\nasync function processRequest(data) {\n  \u002F\u002F Your business logic here\n  const result = await docClient.send(new GetCommand({\n    TableName: process.env.TABLE_NAME,\n    Key: { id: data.id }\n  }));\n  return result.Item;\n}\n```\n\n```python\n# Python Lambda Handler\n# handler.py\n\nimport json\nimport os\nimport logging\nimport boto3\nfrom botocore.exceptions import ClientError\n\n# Initialize outside handler (reused across invocations)\nlogger = logging.getLogger()\nlogger.setLevel(logging.INFO)\n\ndynamodb = boto3.resource('dynamodb')\ntable = dynamodb.Table(os.environ['TABLE_NAME'])\n\ndef handler(event, context):\n    try:\n        # Parse input\n        body = json.loads(event.get('body', '{}')) if isinstance(event.get('body'), str) else event.get('body', {})\n\n        # Business logic\n        result = process_request(body)\n\n        return {\n            'statusCode': 200,\n            'headers': {\n                'Content-Type': 'application\u002Fjson',\n                'Access-Control-Allow-Origin': '*'\n            },\n            'body': json.dumps(result)\n        }\n\n    except ClientError as e:\n        logger.error(f\"DynamoDB error: {e.response['Error']['Message']}\")\n        return error_response(500, 'Database error')\n\n    except json.JSONDecodeError:\n        return error_response(400, 'Invalid JSON')\n\n    except Exception as e:\n        logger.error(f\"Unexpected error: {str(e)}\", exc_info=True)\n        return error_response(500, 'Internal server error')\n\ndef process_request(data):\n    response = table.get_item(Key={'id': data['id']})\n    return response.get('Item')\n\ndef error_response(status_code, message):\n    return {\n        'statusCode': status_code,\n        'headers': {'Content-Type': 'application\u002Fjson'},\n        'body': json.dumps({'error': message})\n    }\n```\n\n### Best_practices\n\n- Initialize clients outside handler (reused across warm invocations)\n- Always return proper API Gateway response format\n- Log with structured JSON for CloudWatch Insights\n- Include request ID in error logs for tracing\n\n### API Gateway Integration Pattern\n\nREST API and HTTP API integration with Lambda\n\n**When to use**: Building REST APIs backed by Lambda,Need HTTP endpoints for functions\n\n```yaml\n# template.yaml (SAM)\nAWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\n\nGlobals:\n  Function:\n    Runtime: nodejs20.x\n    Timeout: 30\n    MemorySize: 256\n    Environment:\n      Variables:\n        TABLE_NAME: !Ref ItemsTable\n\nResources:\n  # HTTP API (recommended for simple use cases)\n  HttpApi:\n    Type: AWS::Serverless::HttpApi\n    Properties:\n      StageName: prod\n      CorsConfiguration:\n        AllowOrigins:\n          - \"*\"\n        AllowMethods:\n          - GET\n          - POST\n          - DELETE\n        AllowHeaders:\n          - \"*\"\n\n  # Lambda Functions\n  GetItemFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: src\u002Fhandlers\u002Fget.handler\n      Events:\n        GetItem:\n          Type: HttpApi\n          Properties:\n            ApiId: !Ref HttpApi\n            Path: \u002Fitems\u002F{id}\n            Method: GET\n      Policies:\n        - DynamoDBReadPolicy:\n            TableName: !Ref ItemsTable\n\n  CreateItemFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: src\u002Fhandlers\u002Fcreate.handler\n      Events:\n        CreateItem:\n          Type: HttpApi\n          Properties:\n            ApiId: !Ref HttpApi\n            Path: \u002Fitems\n            Method: POST\n      Policies:\n        - DynamoDBCrudPolicy:\n            TableName: !Ref ItemsTable\n\n  # DynamoDB Table\n  ItemsTable:\n    Type: AWS::DynamoDB::Table\n    Properties:\n      AttributeDefinitions:\n        - AttributeName: id\n          AttributeType: S\n      KeySchema:\n        - AttributeName: id\n          KeyType: HASH\n      BillingMode: PAY_PER_REQUEST\n\nOutputs:\n  ApiUrl:\n    Value: !Sub \"https:\u002F\u002F${HttpApi}.execute-api.${AWS::Region}.amazonaws.com\u002Fprod\"\n```\n\n```javascript\n\u002F\u002F src\u002Fhandlers\u002Fget.js\nconst { getItem } = require('..\u002Flib\u002Fdynamodb');\n\nexports.handler = async (event) => {\n  const id = event.pathParameters?.id;\n\n  if (!id) {\n    return {\n      statusCode: 400,\n      body: JSON.stringify({ error: 'Missing id parameter' })\n    };\n  }\n\n  const item = await getItem(id);\n\n  if (!item) {\n    return {\n      statusCode: 404,\n      body: JSON.stringify({ error: 'Item not found' })\n    };\n  }\n\n  return {\n    statusCode: 200,\n    body: JSON.stringify(item)\n  };\n};\n```\n\n### Structure\n\nproject\u002F\n├── template.yaml      # SAM template\n├── src\u002F\n│   ├── handlers\u002F\n│   │   ├── get.js\n│   │   ├── create.js\n│   │   └── delete.js\n│   └── lib\u002F\n│       └── dynamodb.js\n└── events\u002F\n    └── event.json     # Test events\n\n### Api_comparison\n\n- Http_api:\n  - Lower latency (~10ms)\n  - Lower cost (50-70% cheaper)\n  - Simpler, fewer features\n  - Best for: Most REST APIs\n- Rest_api:\n  - More features (caching, request validation, WAF)\n  - Usage plans and API keys\n  - Request\u002Fresponse transformation\n  - Best for: Complex APIs, enterprise features\n\n### Event-Driven SQS Pattern\n\nLambda triggered by SQS for reliable async processing\n\n**When to use**: Decoupled, asynchronous processing,Need retry logic and DLQ,Processing messages in batches\n\n```yaml\n# template.yaml\nResources:\n  ProcessorFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: src\u002Fhandlers\u002Fprocessor.handler\n      Events:\n        SQSEvent:\n          Type: SQS\n          Properties:\n            Queue: !GetAtt ProcessingQueue.Arn\n            BatchSize: 10\n            FunctionResponseTypes:\n              - ReportBatchItemFailures  # Partial batch failure handling\n\n  ProcessingQueue:\n    Type: AWS::SQS::Queue\n    Properties:\n      VisibilityTimeout: 180  # 6x Lambda timeout\n      RedrivePolicy:\n        deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn\n        maxReceiveCount: 3\n\n  DeadLetterQueue:\n    Type: AWS::SQS::Queue\n    Properties:\n      MessageRetentionPeriod: 1209600  # 14 days\n```\n\n```javascript\n\u002F\u002F src\u002Fhandlers\u002Fprocessor.js\nexports.handler = async (event) => {\n  const batchItemFailures = [];\n\n  for (const record of event.Records) {\n    try {\n      const body = JSON.parse(record.body);\n      await processMessage(body);\n    } catch (error) {\n      console.error(`Failed to process message ${record.messageId}:`, error);\n      \u002F\u002F Report this item as failed (will be retried)\n      batchItemFailures.push({\n        itemIdentifier: record.messageId\n      });\n    }\n  }\n\n  \u002F\u002F Return failed items for retry\n  return { batchItemFailures };\n};\n\nasync function processMessage(message) {\n  \u002F\u002F Your processing logic\n  console.log('Processing:', message);\n\n  \u002F\u002F Simulate work\n  await saveToDatabase(message);\n}\n```\n\n```python\n# Python version\nimport json\nimport logging\n\nlogger = logging.getLogger()\n\ndef handler(event, context):\n    batch_item_failures = []\n\n    for record in event['Records']:\n        try:\n            body = json.loads(record['body'])\n            process_message(body)\n        except Exception as e:\n            logger.error(f\"Failed to process {record['messageId']}: {e}\")\n            batch_item_failures.append({\n                'itemIdentifier': record['messageId']\n            })\n\n    return {'batchItemFailures': batch_item_failures}\n```\n\n### Best_practices\n\n- Set VisibilityTimeout to 6x Lambda timeout\n- Use ReportBatchItemFailures for partial batch failure\n- Always configure a DLQ for poison messages\n- Process messages idempotently\n\n### DynamoDB Streams Pattern\n\nReact to DynamoDB table changes with Lambda\n\n**When to use**: Real-time reactions to data changes,Cross-region replication,Audit logging, notifications\n\n```yaml\n# template.yaml\nResources:\n  ItemsTable:\n    Type: AWS::DynamoDB::Table\n    Properties:\n      TableName: items\n      AttributeDefinitions:\n        - AttributeName: id\n          AttributeType: S\n      KeySchema:\n        - AttributeName: id\n          KeyType: HASH\n      BillingMode: PAY_PER_REQUEST\n      StreamSpecification:\n        StreamViewType: NEW_AND_OLD_IMAGES\n\n  StreamProcessorFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: src\u002Fhandlers\u002Fstream.handler\n      Events:\n        Stream:\n          Type: DynamoDB\n          Properties:\n            Stream: !GetAtt ItemsTable.StreamArn\n            StartingPosition: TRIM_HORIZON\n            BatchSize: 100\n            MaximumRetryAttempts: 3\n            DestinationConfig:\n              OnFailure:\n                Destination: !GetAtt StreamDLQ.Arn\n\n  StreamDLQ:\n    Type: AWS::SQS::Queue\n```\n\n```javascript\n\u002F\u002F src\u002Fhandlers\u002Fstream.js\nexports.handler = async (event) => {\n  for (const record of event.Records) {\n    const eventName = record.eventName;  \u002F\u002F INSERT, MODIFY, REMOVE\n\n    \u002F\u002F Unmarshall DynamoDB format to plain JS objects\n    const newImage = record.dynamodb.NewImage\n      ? unmarshall(record.dynamodb.NewImage)\n      : null;\n    const oldImage = record.dynamodb.OldImage\n      ? unmarshall(record.dynamodb.OldImage)\n      : null;\n\n    console.log(`${eventName}: `, { newImage, oldImage });\n\n    switch (eventName) {\n      case 'INSERT':\n        await handleInsert(newImage);\n        break;\n      case 'MODIFY':\n        await handleModify(oldImage, newImage);\n        break;\n      case 'REMOVE':\n        await handleRemove(oldImage);\n        break;\n    }\n  }\n};\n\n\u002F\u002F Use AWS SDK v3 unmarshall\nconst { unmarshall } = require('@aws-sdk\u002Futil-dynamodb');\n```\n\n### Stream_view_types\n\n- KEYS_ONLY: Only key attributes\n- NEW_IMAGE: After modification\n- OLD_IMAGE: Before modification\n- NEW_AND_OLD_IMAGES: Both before and after\n\n### Cold Start Optimization Pattern\n\nMinimize Lambda cold start latency\n\n**When to use**: Latency-sensitive applications,User-facing APIs,High-traffic functions\n\n## 1. Optimize Package Size\n\n```javascript\n\u002F\u002F Use modular AWS SDK v3 imports\n\u002F\u002F GOOD - only imports what you need\nconst { DynamoDBClient } = require('@aws-sdk\u002Fclient-dynamodb');\nconst { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk\u002Flib-dynamodb');\n\n\u002F\u002F BAD - imports entire SDK\nconst AWS = require('aws-sdk');  \u002F\u002F Don't do this!\n```\n\n## 2. Use SnapStart (Java\u002F.NET)\n\n```yaml\n# template.yaml\nResources:\n  JavaFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: com.example.Handler::handleRequest\n      Runtime: java21\n      SnapStart:\n        ApplyOn: PublishedVersions  # Enable SnapStart\n      AutoPublishAlias: live\n```\n\n## 3. Right-size Memory\n\n```yaml\n# More memory = more CPU = faster init\nResources:\n  FastFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      MemorySize: 1024  # 1GB gets full vCPU\n      Timeout: 30\n```\n\n## 4. Provisioned Concurrency (when needed)\n\n```yaml\nResources:\n  CriticalFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Handler: src\u002Fhandlers\u002Fcritical.handler\n      AutoPublishAlias: live\n\n  ProvisionedConcurrency:\n    Type: AWS::Lambda::ProvisionedConcurrencyConfig\n    Properties:\n      FunctionName: !Ref CriticalFunction\n      Qualifier: live\n      ProvisionedConcurrentExecutions: 5\n```\n\n## 5. Keep Init Light\n\n```python\n# GOOD - Lazy initialization\n_table = None\n\ndef get_table():\n    global _table\n    if _table is None:\n        dynamodb = boto3.resource('dynamodb')\n        _table = dynamodb.Table(os.environ['TABLE_NAME'])\n    return _table\n\ndef handler(event, context):\n    table = get_table()  # Only initializes on first use\n    # ...\n```\n\n### Optimization_priority\n\n- 1: Reduce package size (biggest impact)\n- 2: Use SnapStart for Java\u002F.NET\n- 3: Increase memory for faster init\n- 4: Delay heavy imports\n- 5: Provisioned concurrency (last resort)\n\n### SAM Local Development Pattern\n\nLocal testing and debugging with SAM CLI\n\n**When to use**: Local development and testing,Debugging Lambda functions,Testing API Gateway locally\n\n```bash\n# Install SAM CLI\npip install aws-sam-cli\n\n# Initialize new project\nsam init --runtime nodejs20.x --name my-api\n\n# Build the project\nsam build\n\n# Run locally\nsam local start-api\n\n# Invoke single function\nsam local invoke GetItemFunction --event events\u002Fget.json\n\n# Local debugging (Node.js with VS Code)\nsam local invoke --debug-port 5858 GetItemFunction\n\n# Deploy\nsam deploy --guided\n```\n\n```json\n\u002F\u002F events\u002Fget.json (test event)\n{\n  \"pathParameters\": {\n    \"id\": \"123\"\n  },\n  \"httpMethod\": \"GET\",\n  \"path\": \"\u002Fitems\u002F123\"\n}\n```\n\n```json\n\u002F\u002F .vscode\u002Flaunch.json (for debugging)\n{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Attach to SAM CLI\",\n      \"type\": \"node\",\n      \"request\": \"attach\",\n      \"address\": \"localhost\",\n      \"port\": 5858,\n      \"localRoot\": \"${workspaceRoot}\u002Fsrc\",\n      \"remoteRoot\": \"\u002Fvar\u002Ftask\u002Fsrc\",\n      \"protocol\": \"inspector\"\n    }\n  ]\n}\n```\n\n### Commands\n\n- Sam_build: Build Lambda deployment packages\n- Sam_local_start_api: Start local API Gateway\n- Sam_local_invoke: Invoke single function\n- Sam_deploy: Deploy to AWS\n- Sam_logs: Tail CloudWatch logs\n\n### CDK Serverless Pattern\n\nInfrastructure as code with AWS CDK\n\n**When to use**: Complex infrastructure beyond Lambda,Prefer programming languages over YAML,Need reusable constructs\n\n```typescript\n\u002F\u002F lib\u002Fapi-stack.ts\nimport * as cdk from 'aws-cdk-lib';\nimport * as lambda from 'aws-cdk-lib\u002Faws-lambda';\nimport * as apigateway from 'aws-cdk-lib\u002Faws-apigateway';\nimport * as dynamodb from 'aws-cdk-lib\u002Faws-dynamodb';\nimport { Construct } from 'constructs';\n\nexport class ApiStack extends cdk.Stack {\n  constructor(scope: Construct, id: string, props?: cdk.StackProps) {\n    super(scope, id, props);\n\n    \u002F\u002F DynamoDB Table\n    const table = new dynamodb.Table(this, 'ItemsTable', {\n      partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },\n      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,\n      removalPolicy: cdk.RemovalPolicy.DESTROY, \u002F\u002F For dev only\n    });\n\n    \u002F\u002F Lambda Function\n    const getItemFn = new lambda.Function(this, 'GetItemFunction', {\n      runtime: lambda.Runtime.NODEJS_20_X,\n      handler: 'get.handler',\n      code: lambda.Code.fromAsset('src\u002Fhandlers'),\n      environment: {\n        TABLE_NAME: table.tableName,\n      },\n      memorySize: 256,\n      timeout: cdk.Duration.seconds(30),\n    });\n\n    \u002F\u002F Grant permissions\n    table.grantReadData(getItemFn);\n\n    \u002F\u002F API Gateway\n    const api = new apigateway.RestApi(this, 'ItemsApi', {\n      restApiName: 'Items Service',\n      defaultCorsPreflightOptions: {\n        allowOrigins: apigateway.Cors.ALL_ORIGINS,\n        allowMethods: apigateway.Cors.ALL_METHODS,\n      },\n    });\n\n    const items = api.root.addResource('items');\n    const item = items.addResource('{id}');\n\n    item.addMethod('GET', new apigateway.LambdaIntegration(getItemFn));\n\n    \u002F\u002F Output API URL\n    new cdk.CfnOutput(this, 'ApiUrl', {\n      value: api.url,\n    });\n  }\n}\n```\n\n```bash\n# CDK commands\nnpm install -g aws-cdk\ncdk init app --language typescript\ncdk synth    # Generate CloudFormation\ncdk diff     # Show changes\ncdk deploy   # Deploy to AWS\n```\n\n## Sharp Edges\n\n### Cold Start INIT Phase Now Billed (Aug 2025)\n\nSeverity: HIGH\n\nSituation: Running Lambda functions in production\n\nSymptoms:\nUnexplained increase in Lambda costs (10-50% higher).\nBill includes charges for function initialization.\nFunctions with heavy startup logic cost more than expected.\n\nWhy this breaks:\nAs of August 1, 2025, AWS bills the INIT phase the same way it bills\ninvocation duration. Previously, cold start initialization wasn't billed\nfor the full duration.\n\nThis affects functions with:\n- Heavy dependency loading (large packages)\n- Slow initialization code\n- Frequent cold starts (low traffic or poor concurrency)\n\nCold starts now directly impact your bill, not just latency.\n\nRecommended fix:\n\n## Measure your INIT phase\n\n```bash\n# Check CloudWatch Logs for INIT_REPORT\n# Look for Init Duration in milliseconds\n\n# Example log line:\n# INIT_REPORT Init Duration: 423.45 ms\n```\n\n## Reduce INIT duration\n\n```javascript\n\u002F\u002F 1. Minimize package size\n\u002F\u002F Use tree shaking, exclude dev dependencies\n\u002F\u002F npm prune --production\n\n\u002F\u002F 2. Lazy load heavy dependencies\nlet heavyLib = null;\nfunction getHeavyLib() {\n  if (!heavyLib) {\n    heavyLib = require('heavy-library');\n  }\n  return heavyLib;\n}\n\n\u002F\u002F 3. Use AWS SDK v3 modular imports\nconst { S3Client } = require('@aws-sdk\u002Fclient-s3');\n\u002F\u002F NOT: const AWS = require('aws-sdk');\n```\n\n## Use SnapStart for Java\u002F.NET\n\n```yaml\nResources:\n  JavaFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Runtime: java21\n      SnapStart:\n        ApplyOn: PublishedVersions\n```\n\n## Monitor cold start frequency\n\n```javascript\n\u002F\u002F Track cold starts with custom metric\nlet isColdStart = true;\n\nexports.handler = async (event) => {\n  if (isColdStart) {\n    console.log('COLD_START');\n    \u002F\u002F CloudWatch custom metric here\n    isColdStart = false;\n  }\n  \u002F\u002F ...\n};\n```\n\n### Lambda Timeout Misconfiguration\n\nSeverity: HIGH\n\nSituation: Running Lambda functions, especially with external calls\n\nSymptoms:\nFunction times out unexpectedly.\n\"Task timed out after X seconds\" in logs.\nPartial processing with no response.\nSilent failures with no error caught.\n\nWhy this breaks:\nDefault Lambda timeout is only 3 seconds. Maximum is 15 minutes.\n\nCommon timeout causes:\n- Default timeout too short for workload\n- Downstream service taking longer than expected\n- Network issues in VPC\n- Infinite loops or blocking operations\n- S3 downloads larger than expected\n\nLambda terminates at timeout without graceful shutdown.\n\nRecommended fix:\n\n## Set appropriate timeout\n\n```yaml\n# template.yaml\nResources:\n  MyFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      Timeout: 30  # Seconds (max 900)\n      # Set to expected duration + buffer\n```\n\n## Implement timeout awareness\n\n```javascript\nexports.handler = async (event, context) => {\n  \u002F\u002F Get remaining time\n  const remainingTime = context.getRemainingTimeInMillis();\n\n  \u002F\u002F If running low on time, fail gracefully\n  if (remainingTime \u003C 5000) {\n    console.warn('Running low on time, aborting');\n    throw new Error('Insufficient time remaining');\n  }\n\n  \u002F\u002F For long operations, check periodically\n  for (const item of items) {\n    if (context.getRemainingTimeInMillis() \u003C 10000) {\n      \u002F\u002F Save progress and exit gracefully\n      await saveProgress(processedItems);\n      throw new Error('Timeout approaching, saved progress');\n    }\n    await processItem(item);\n  }\n};\n```\n\n## Set downstream timeouts\n\n```javascript\nconst axios = require('axios');\n\n\u002F\u002F Always set timeouts on HTTP calls\nconst response = await axios.get('https:\u002F\u002Fapi.example.com\u002Fdata', {\n  timeout: 5000  \u002F\u002F 5 seconds\n});\n```\n\n### Out of Memory (OOM) Crash\n\nSeverity: HIGH\n\nSituation: Lambda function processing data\n\nSymptoms:\nFunction stops abruptly without error.\nCloudWatch logs appear truncated.\n\"Max Memory Used\" hits configured limit.\nInconsistent behavior under load.\n\nWhy this breaks:\nWhen Lambda exceeds memory allocation, AWS forcibly terminates\nthe runtime. This happens without raising a catchable exception.\n\nCommon causes:\n- Processing large files in memory\n- Memory leaks across invocations\n- Buffering entire response bodies\n- Heavy libraries consuming too much memory\n\nRecommended fix:\n\n## Increase memory allocation\n\n```yaml\nResources:\n  MyFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      MemorySize: 1024  # MB (128-10240)\n      # More memory = more CPU too\n```\n\n## Stream large data\n\n```javascript\n\u002F\u002F BAD - loads entire file into memory\nconst data = await s3.getObject(params).promise();\nconst content = data.Body.toString();\n\n\u002F\u002F GOOD - stream processing\nconst { S3Client, GetObjectCommand } = require('@aws-sdk\u002Fclient-s3');\nconst s3 = new S3Client({});\n\nconst response = await s3.send(new GetObjectCommand(params));\nconst stream = response.Body;\n\n\u002F\u002F Process stream in chunks\nfor await (const chunk of stream) {\n  await processChunk(chunk);\n}\n```\n\n## Monitor memory usage\n\n```javascript\nexports.handler = async (event, context) => {\n  const used = process.memoryUsage();\n  console.log('Memory:', {\n    heapUsed: Math.round(used.heapUsed \u002F 1024 \u002F 1024) + 'MB',\n    heapTotal: Math.round(used.heapTotal \u002F 1024 \u002F 1024) + 'MB'\n  });\n  \u002F\u002F ...\n};\n```\n\n## Use Lambda Power Tuning\n\n```bash\n# Find optimal memory setting\n# https:\u002F\u002Fgithub.com\u002Falexcasalboni\u002Faws-lambda-power-tuning\n```\n\n### VPC-Attached Lambda Cold Start Delay\n\nSeverity: MEDIUM\n\nSituation: Lambda functions in VPC accessing private resources\n\nSymptoms:\nExtremely slow cold starts (was 10+ seconds, now ~100ms).\nTimeouts on first invocation after idle period.\nFunctions work in VPC but slow compared to non-VPC.\n\nWhy this breaks:\nLambda functions in VPC need Elastic Network Interfaces (ENIs).\nAWS improved this significantly with Hyperplane ENIs, but:\n\n- First cold start in VPC still has overhead\n- NAT Gateway issues can cause timeouts\n- Security group misconfig blocks traffic\n- DNS resolution can be slow\n\nRecommended fix:\n\n## Verify VPC configuration\n\n```yaml\nResources:\n  MyFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      VpcConfig:\n        SecurityGroupIds:\n          - !Ref LambdaSecurityGroup\n        SubnetIds:\n          - !Ref PrivateSubnet1\n          - !Ref PrivateSubnet2  # Multiple AZs\n\n  LambdaSecurityGroup:\n    Type: AWS::EC2::SecurityGroup\n    Properties:\n      GroupDescription: Lambda SG\n      VpcId: !Ref VPC\n      SecurityGroupEgress:\n        - IpProtocol: tcp\n          FromPort: 443\n          ToPort: 443\n          CidrIp: 0.0.0.0\u002F0  # Allow HTTPS outbound\n```\n\n## Use VPC endpoints for AWS services\n\n```yaml\n# Avoid NAT Gateway for AWS service calls\nDynamoDBEndpoint:\n  Type: AWS::EC2::VPCEndpoint\n  Properties:\n    ServiceName: !Sub com.amazonaws.${AWS::Region}.dynamodb\n    VpcId: !Ref VPC\n    RouteTableIds:\n      - !Ref PrivateRouteTable\n    VpcEndpointType: Gateway\n\nS3Endpoint:\n  Type: AWS::EC2::VPCEndpoint\n  Properties:\n    ServiceName: !Sub com.amazonaws.${AWS::Region}.s3\n    VpcId: !Ref VPC\n    VpcEndpointType: Gateway\n```\n\n## Only use VPC when necessary\n\nDon't attach Lambda to VPC unless you need:\n- Access to RDS\u002FElastiCache in VPC\n- Access to private EC2 instances\n- Compliance requirements\n\nMost AWS services can be accessed without VPC.\n\n### Node.js Event Loop Not Cleared\n\nSeverity: MEDIUM\n\nSituation: Node.js Lambda function with callbacks or timers\n\nSymptoms:\nFunction takes full timeout duration to return.\n\"Task timed out\" even though logic completed.\nExtra billing for idle time.\n\nWhy this breaks:\nBy default, Lambda waits for the Node.js event loop to be empty\nbefore returning. If you have:\n- Unresolved setTimeout\u002FsetInterval\n- Dangling database connections\n- Pending callbacks\n\nLambda waits until timeout, even if your response was ready.\n\nRecommended fix:\n\n## Tell Lambda not to wait for event loop\n\n```javascript\nexports.handler = async (event, context) => {\n  \u002F\u002F Don't wait for event loop to clear\n  context.callbackWaitsForEmptyEventLoop = false;\n\n  \u002F\u002F Your code here\n  const result = await processRequest(event);\n\n  return {\n    statusCode: 200,\n    body: JSON.stringify(result)\n  };\n};\n```\n\n## Close connections properly\n\n```javascript\n\u002F\u002F For database connections, use connection pooling\n\u002F\u002F or close connections explicitly\n\nconst mysql = require('mysql2\u002Fpromise');\n\nexports.handler = async (event, context) => {\n  context.callbackWaitsForEmptyEventLoop = false;\n\n  const connection = await mysql.createConnection({...});\n  try {\n    const [rows] = await connection.query('SELECT * FROM users');\n    return { statusCode: 200, body: JSON.stringify(rows) };\n  } finally {\n    await connection.end();  \u002F\u002F Always close\n  }\n};\n```\n\n### API Gateway Payload Size Limits\n\nSeverity: MEDIUM\n\nSituation: Returning large responses or receiving large requests\n\nSymptoms:\n\"413 Request Entity Too Large\" error\n\"Execution failed due to configuration error: Malformed Lambda proxy response\"\nResponse truncated or failed\n\nWhy this breaks:\nAPI Gateway has hard payload limits:\n- REST API: 10 MB request\u002Fresponse\n- HTTP API: 10 MB request\u002Fresponse\n- Lambda itself: 6 MB sync response, 256 KB async\n\nExceeding these causes failures that may not be obvious.\n\nRecommended fix:\n\n## For large file uploads\n\n```javascript\n\u002F\u002F Use presigned S3 URLs instead of passing through API Gateway\n\nconst { S3Client, PutObjectCommand } = require('@aws-sdk\u002Fclient-s3');\nconst { getSignedUrl } = require('@aws-sdk\u002Fs3-request-presigner');\n\nexports.handler = async (event) => {\n  const s3 = new S3Client({});\n\n  const command = new PutObjectCommand({\n    Bucket: process.env.BUCKET_NAME,\n    Key: `uploads\u002F${Date.now()}.file`\n  });\n\n  const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 300 });\n\n  return {\n    statusCode: 200,\n    body: JSON.stringify({ uploadUrl })\n  };\n};\n```\n\n## For large responses\n\n```javascript\n\u002F\u002F Store in S3, return presigned download URL\nexports.handler = async (event) => {\n  const largeData = await generateLargeReport();\n\n  await s3.send(new PutObjectCommand({\n    Bucket: process.env.BUCKET_NAME,\n    Key: `reports\u002F${reportId}.json`,\n    Body: JSON.stringify(largeData)\n  }));\n\n  const downloadUrl = await getSignedUrl(s3,\n    new GetObjectCommand({\n      Bucket: process.env.BUCKET_NAME,\n      Key: `reports\u002F${reportId}.json`\n    }),\n    { expiresIn: 3600 }\n  );\n\n  return {\n    statusCode: 200,\n    body: JSON.stringify({ downloadUrl })\n  };\n};\n```\n\n### Infinite Loop or Recursive Invocation\n\nSeverity: HIGH\n\nSituation: Lambda triggered by events\n\nSymptoms:\nRunaway costs.\nThousands of invocations in minutes.\nCloudWatch logs show repeated invocations.\nLambda writing to source bucket\u002Ftable that triggers it.\n\nWhy this breaks:\nLambda can accidentally trigger itself:\n- S3 trigger writes back to same bucket\n- DynamoDB trigger updates same table\n- SNS publishes to topic that triggers it\n- Step Functions with wrong error handling\n\nRecommended fix:\n\n## Use different buckets\u002Fprefixes\n\n```yaml\n# S3 trigger with prefix filter\nEvents:\n  S3Event:\n    Type: S3\n    Properties:\n      Bucket: !Ref InputBucket\n      Events: s3:ObjectCreated:*\n      Filter:\n        S3Key:\n          Rules:\n            - Name: prefix\n              Value: uploads\u002F  # Only trigger on uploads\u002F\n\n# Output to different bucket or prefix\n# OutputBucket or processed\u002F prefix\n```\n\n## Add idempotency checks\n\n```javascript\nexports.handler = async (event) => {\n  for (const record of event.Records) {\n    const key = record.s3.object.key;\n\n    \u002F\u002F Skip if this is a processed file\n    if (key.startsWith('processed\u002F')) {\n      console.log('Skipping already processed file:', key);\n      continue;\n    }\n\n    \u002F\u002F Process and write to different location\n    await processFile(key);\n    await writeToS3(`processed\u002F${key}`, result);\n  }\n};\n```\n\n## Set reserved concurrency as circuit breaker\n\n```yaml\nResources:\n  RiskyFunction:\n    Type: AWS::Serverless::Function\n    Properties:\n      ReservedConcurrentExecutions: 10  # Max 10 parallel\n      # Limits blast radius of runaway invocations\n```\n\n## Monitor with CloudWatch alarms\n\n```yaml\nInvocationAlarm:\n  Type: AWS::CloudWatch::Alarm\n  Properties:\n    MetricName: Invocations\n    Namespace: AWS\u002FLambda\n    Statistic: Sum\n    Period: 60\n    EvaluationPeriods: 1\n    Threshold: 1000  # Alert if >1000 invocations\u002Fmin\n    ComparisonOperator: GreaterThanThreshold\n```\n\n## Validation Checks\n\n### Hardcoded AWS Credentials\n\nSeverity: ERROR\n\nAWS credentials must never be hardcoded\n\nMessage: Hardcoded AWS access key detected. Use IAM roles or environment variables.\n\n### AWS Secret Key in Source Code\n\nSeverity: ERROR\n\nSecret keys should use Secrets Manager or environment variables\n\nMessage: Hardcoded AWS secret key. Use IAM roles or Secrets Manager.\n\n### Overly Permissive IAM Policy\n\nSeverity: WARNING\n\nAvoid wildcard permissions in Lambda IAM roles\n\nMessage: Overly permissive IAM policy. Use least privilege principle.\n\n### Lambda Handler Without Error Handling\n\nSeverity: WARNING\n\nLambda handlers should have try\u002Fcatch for graceful errors\n\nMessage: Lambda handler without error handling. Add try\u002Fcatch.\n\n### Missing callbackWaitsForEmptyEventLoop\n\nSeverity: INFO\n\nNode.js handlers should set callbackWaitsForEmptyEventLoop\n\nMessage: Consider setting context.callbackWaitsForEmptyEventLoop = false\n\n### Default Memory Configuration\n\nSeverity: INFO\n\nDefault 128MB may be too low for many workloads\n\nMessage: Using default 128MB memory. Consider increasing for better performance.\n\n### Low Timeout Configuration\n\nSeverity: WARNING\n\nVery low timeout may cause unexpected failures\n\nMessage: Timeout of 1-3 seconds may be too low. Increase if making external calls.\n\n### No Dead Letter Queue Configuration\n\nSeverity: WARNING\n\nAsync functions should have DLQ for failed invocations\n\nMessage: No DLQ configured. Add for async invocations.\n\n### Importing Full AWS SDK v2\n\nSeverity: WARNING\n\nImport specific clients from AWS SDK v3 for smaller packages\n\nMessage: Importing full AWS SDK. Use modular SDK v3 imports for smaller packages.\n\n### Hardcoded DynamoDB Table Name\n\nSeverity: WARNING\n\nTable names should come from environment variables\n\nMessage: Hardcoded table name. Use environment variable for portability.\n\n## Collaboration\n\n### Delegation Triggers\n\n- user needs GCP serverless -> gcp-cloud-run (Cloud Run for containers, Cloud Functions for events)\n- user needs Azure serverless -> azure-functions (Azure Functions, Logic Apps)\n- user needs database design -> postgres-wizard (RDS design, or use DynamoDB patterns)\n- user needs authentication -> auth-specialist (Cognito, API Gateway authorizers)\n- user needs complex workflows -> workflow-automation (Step Functions, EventBridge)\n- user needs AI integration -> llm-architect (Lambda calling Bedrock or external LLMs)\n\n## When to Use\nUse this skill when the request clearly matches the capabilities and patterns described above.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,112,859,"2026-05-16 13:04:51",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":19},"b293645f-d8e0-474f-92cf-4a4df789ef08","1.0.0","aws-serverless.zip",11030,"uploads\u002Fskills\u002F5ee212a6-6ef5-465d-80be-256caca83b08\u002Faws-serverless.zip","7aba391c82fc154e792cbd9d9aa957d1338121556b1a5ffd5b0334041f094a87","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":32487}]",{"code":43,"message":44,"data":45},200,"success",{"items":46,"stats":47,"page":50},[],{"averageRating":48,"totalRatings":48,"ratingCounts":49},0,[48,48,48,48,48],{"limit":51,"offset":48,"hasMore":52,"nextOffset":51,"ratedOnly":16},15,false]