项目文件夹

文件
wehub-resource-sync bb5c75ce05
Component Security Validation / Security Audit (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:58 +08:00

1 行
8.0 KiB
JSON

{"content": "---\nname: aws-serverless\ndescription: \"Specialized skill for building production-ready serverless applications on AWS. Covers Lambda functions, API Gateway, DynamoDB, SQS/SNS event-driven patterns, SAM/CDK deployment, and cold start optimization.\"\nsource: vibeship-spawner-skills (Apache 2.0)\n---\n\n# AWS Serverless\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```python\n```javascript\n// Node.js Lambda Handler\n// handler.js\n\n// Initialize outside handler (reused across invocations)\nconst { DynamoDBClient } = require('@aws-sdk/client-dynamodb');\nconst { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');\n\nconst client = new DynamoDBClient({});\nconst docClient = DynamoDBDocumentClient.from(client);\n\n// Handler function\nexports.handler = async (event, context) => {\n // Optional: Don't wait for event loop to clear (Node.js)\n context.callbackWaitsForEmptyEventLoop = false;\n\n try {\n // Parse input based on event source\n const body = typeof event.body === 'string'\n ? JSON.parse(event.body)\n : event.body;\n\n // Business logic\n const result = await processRequest(body);\n\n // Return API Gateway compatible response\n return {\n statusCode: 200,\n headers: {\n 'Content-Type': 'application/json',\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/json' },\n body: JSON.stringify({\n error: error.message || 'Internal server error'\n })\n };\n }\n};\n\nasync function processRequest(data) {\n // 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 i\n```\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```javascript\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/handlers/get.handler\n Events:\n GetItem:\n Type: HttpApi\n Properties:\n ApiId: !Ref HttpApi\n Path: /items/{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/handlers/create.handler\n Events:\n CreateItem:\n Type: HttpApi\n Properties:\n ApiId: !Ref HttpApi\n Path: /items\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://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/prod\"\n```\n\n```javascript\n// src/handlers/get.js\nconst { getItem } = require('../lib/dynamodb');\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 =\n```\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```python\n```yaml\n# template.yaml\nResources:\n ProcessorFunction:\n Type: AWS::Serverless::Function\n Properties:\n Handler: src/handlers/processor.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// src/handlers/processor.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 // Report this item as failed (will be retried)\n batchItemFailures.push({\n itemIdentifier: record.messageId\n });\n }\n }\n\n // Return failed items for retry\n return { batchItemFailures };\n};\n\nasync function processMessage(message) {\n // Your processing logic\n console.log('Processing:', message);\n\n // 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_ite\n```\n\n## Anti-Patterns\n\n### ❌ Monolithic Lambda\n\n**Why bad**: Large deployment packages cause slow cold starts.\nHard to scale individual operations.\nUpdates affect entire system.\n\n### ❌ Large Dependencies\n\n**Why bad**: Increases deployment package size.\nSlows down cold starts significantly.\nMost of SDK/library may be unused.\n\n### ❌ Synchronous Calls in VPC\n\n**Why bad**: VPC-attached Lambdas have ENI setup overhead.\nBlocking DNS lookups or connections worsen cold starts.\n\n## ⚠️ Sharp Edges\n\n| Issue | Severity | Solution |\n|-------|----------|----------|\n| Issue | high | ## Measure your INIT phase |\n| Issue | high | ## Set appropriate timeout |\n| Issue | high | ## Increase memory allocation |\n| Issue | medium | ## Verify VPC configuration |\n| Issue | medium | ## Tell Lambda not to wait for event loop |\n| Issue | medium | ## For large file uploads |\n| Issue | high | ## Use different buckets/prefixes |\n"}