serverless-architecture

安装量: 137
排名: #6302

安装

npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill serverless-architecture

Serverless Architecture Overview

Serverless architecture enables building complete applications without managing servers. Design event-driven, scalable systems using managed compute services, databases, and messaging systems. Pay only for actual usage with automatic scaling.

When to Use Event-driven applications API backends and microservices Real-time data processing Batch jobs and scheduled tasks Workflow automation IoT data pipelines Multi-tenant SaaS applications Mobile app backends Implementation Examples 1. Serverless Application Architecture

serverless.yml - Serverless Framework

service: my-app

frameworkVersion: '3'

provider: name: aws runtime: nodejs18.x region: us-east-1 stage: ${opt:stage, 'dev'} memorySize: 256 timeout: 30 environment: STAGE: ${self:provider.stage} DYNAMODB_TABLE: ${self:service}-users-${self:provider.stage} SNS_TOPIC_ARN: arn:aws:sns:${self:provider.region}:${aws:accountId}:my-topic httpApi: cors: true iam: role: statements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${self:provider.region}:${aws:accountId}:table/${self:provider.environment.DYNAMODB_TABLE}" - Effect: Allow Action: - sns:Publish Resource: ${self:provider.environment.SNS_TOPIC_ARN}

functions: # HTTP API endpoints getUser: handler: src/handlers/getUser.handler events: - httpApi: path: /api/users/{id} method: GET

listUsers: handler: src/handlers/listUsers.handler events: - httpApi: path: /api/users method: GET

createUser: handler: src/handlers/createUser.handler events: - httpApi: path: /api/users method: POST

# Event-driven functions processUserCreated: handler: src/handlers/processUserCreated.handler events: - sns: arn: arn:aws:sns:${self:provider.region}:${aws:accountId}:user-created topicName: user-created

processPendingOrders: handler: src/handlers/processPendingOrders.handler timeout: 300 events: - schedule: rate: cron(0 2 * * ? *) enabled: true

# S3 event handler processImageUpload: handler: src/handlers/processImageUpload.handler events: - s3: bucket: my-uploads-${self:provider.stage} event: s3:ObjectCreated:* rules: - prefix: uploads/ - suffix: .jpg

# SQS queue processor processQueue: handler: src/handlers/processQueue.handler events: - sqs: arn: arn:aws:sqs:${self:provider.region}:${aws:accountId}:my-queue batchSize: 10 batchWindow: 5

resources: Resources: UsersTable: Type: AWS::DynamoDB::Table Properties: TableName: ${self:provider.environment.DYNAMODB_TABLE} AttributeDefinitions: - AttributeName: id AttributeType: S - AttributeName: createdAt AttributeType: N KeySchema: - AttributeName: id KeyType: HASH - AttributeName: createdAt KeyType: RANGE BillingMode: PAY_PER_REQUEST StreamSpecification: StreamViewType: NEW_AND_OLD_IMAGES

UserNotificationTopic:
  Type: AWS::SNS::Topic
  Properties:
    TopicName: user-created-${self:provider.stage}

ProcessingQueue:
  Type: AWS::SQS::Queue
  Properties:
    QueueName: my-queue-${self:provider.stage}
    VisibilityTimeout: 300
    MessageRetentionPeriod: 1209600

plugins: - serverless-python-requirements - serverless-plugin-tracing - serverless-offline - serverless-dynamodb-local

  1. Event-Driven Lambda Handler Pattern // src/handlers/processUserCreated.js const AWS = require('aws-sdk'); const dynamodb = new AWS.DynamoDB.DocumentClient();

const userService = require('../services/userService'); const emailService = require('../services/emailService');

exports.handler = async (event, context) => { console.log('Processing user created event:', JSON.stringify(event));

try { // Parse SNS message const records = event.Records;

for (const record of records) {
  const message = JSON.parse(record.Sns.Message);
  const userId = message.userId;

  // Get user details
  const user = await userService.getUser(userId);

  // Send welcome email
  await emailService.sendWelcomeEmail(user);

  // Initialize user preferences
  await dynamodb.put({
    TableName: process.env.DYNAMODB_TABLE,
    Item: {
      id: userId,
      preferences: {
        newsletter: true,
        notifications: true
      },
      createdAt: Date.now()
    }
  }).promise();

  // Log success
  console.log(`Successfully processed user creation for ${userId}`);
}

return {
  statusCode: 200,
  body: JSON.stringify({ message: 'Processed' })
};

} catch (error) { console.error('Error processing event:', error); throw error; // SNS will retry } };

// src/handlers/processImageUpload.js const AWS = require('aws-sdk'); const s3 = new AWS.S3(); const rekognition = new AWS.Rekognition();

exports.handler = async (event, context) => { try { for (const record of event.Records) { const bucket = record.s3.bucket.name; const key = record.s3.object.key;

  console.log(`Processing image: s3://${bucket}/${key}`);

  // Analyze image with Rekognition
  const labels = await rekognition.detectLabels({
    Image: {
      S3Object: {
        Bucket: bucket,
        Name: key
      }
    },
    MaxLabels: 10,
    MinConfidence: 70
  }).promise();

  // Create thumbnail
  await createThumbnail(bucket, key);

  // Index metadata
  await indexMetadata(bucket, key, labels);

  console.log(`Completed processing ${key}`);
}

} catch (error) { console.error('Error processing S3 event:', error); throw error; } };

async function createThumbnail(bucket, key) { // Implementation return true; }

async function indexMetadata(bucket, key, labels) { // Implementation return true; }

  1. Orchestration with Step Functions { "Comment": "Order processing workflow", "StartAt": "ValidateOrder", "States": { "ValidateOrder": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:validateOrder", "Next": "CheckInventory", "Catch": [ { "ErrorEquals": ["InvalidOrder"], "Next": "OrderFailed" } ] }, "CheckInventory": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:checkInventory", "Next": "InventoryDecision" }, "InventoryDecision": { "Type": "Choice", "Choices": [ { "Variable": "$.inStock", "BooleanEquals": true, "Next": "ProcessPayment" } ], "Default": "OutOfStock" }, "ProcessPayment": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:processPayment", "Next": "PaymentDecision", "Retry": [ { "ErrorEquals": ["PaymentError"], "IntervalSeconds": 2, "MaxAttempts": 3, "BackoffRate": 2.0 } ] }, "PaymentDecision": { "Type": "Choice", "Choices": [ { "Variable": "$.paymentApproved", "BooleanEquals": true, "Next": "ShipOrder" } ], "Default": "PaymentFailed" }, "ShipOrder": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:shipOrder", "Next": "NotifyCustomer" }, "NotifyCustomer": { "Type": "Task", "Resource": "arn:aws:states:::sns:publish", "Parameters": { "TopicArn": "arn:aws:sns:region:account:order-updates", "Message": { "orderId.$": "$.orderId", "status": "shipped" } }, "Next": "OrderSuccess" }, "OrderSuccess": { "Type": "Succeed" }, "OutOfStock": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:notifyOutOfStock", "Next": "OrderFailed" }, "PaymentFailed": { "Type": "Task", "Resource": "arn:aws:lambda:region:account:function:handlePaymentFailure", "Next": "OrderFailed" }, "OrderFailed": { "Type": "Fail", "Error": "OrderFailed", "Cause": "Order processing failed" } } }

  2. Monitoring and Observability

Monitoring helper

import json import logging from aws_lambda_powertools import Logger, Tracer, Metrics from aws_lambda_powertools.utilities.typing import LambdaContext

logger = Logger() tracer = Tracer() metrics = Metrics()

@logger.inject_lambda_context @tracer.capture_lambda_handler def handler(event: dict, context: LambdaContext) -> dict: try: logger.info("Processing event", extra={"event": event})

    # Add custom metrics
    metrics.add_metric(
        name="OrderProcessed",
        unit="Count",
        value=1
    )
    metrics.add_metric(
        name="OrderAmount",
        unit="None",
        value=event.get('amount', 0)
    )

    # Business logic
    result = process_order(event)

    logger.info("Order processed successfully", extra={"orderId": result['orderId']})
    return result

except Exception as e:
    logger.exception("Error processing order")
    metrics.add_metric(
        name="OrderFailed",
        unit="Count",
        value=1
    )
    raise

finally:
    metrics.flush()

def process_order(event): return {"orderId": event.get("id"), "status": "completed"}

Best Practices ✅ DO Design idempotent functions Use event sources efficiently Implement proper error handling Monitor with CloudWatch/Application Insights Use infrastructure as code Implement distributed tracing Version functions for safe deployments Use environment variables for configuration ❌ DON'T Create long-running functions Store state in functions Ignore cold start optimization Use synchronous chains Skip testing Hardcode configuration Deploy without monitoring Architecture Patterns Event sourcing for audit trails CQRS for read-write optimization Saga pattern for distributed transactions Dead letter queues for failure handling Fan-out/fan-in for parallel processing Circuit breaker for resilience Resources AWS Serverless Architecture Serverless Framework Documentation Lambda Best Practices

返回排行榜