aws-serverless

$npx mdskill add tranhieutt/software_development_department/aws-serverless

Provides AWS serverless patterns for Lambda, API Gateway, DynamoDB, and SAM/CDK.

  • Solves cold starts, timeouts, and CORS issues in serverless apps.
  • Depends on AWS SDK, SAM, CDK, and serverless.yml files.
  • Recommends patterns based on file paths and user mentions of serverless services.
  • Delivers code snippets and configuration rules for Lambda, SQS, and API Gateway.

SKILL.md

.github/skills/aws-serverlessView on GitHub ↗
---
name: aws-serverless
type: reference
description: "Provides AWS serverless architecture patterns for Lambda, API Gateway, DynamoDB, SQS, and SAM/CDK. Use when working with AWS serverless files (serverless.yml, CDK stacks) or when the user mentions Lambda, API Gateway, serverless, or AWS SAM."
paths: ["**/serverless.yml", "**/template.yaml", "**/cdk/**", "**/sam/**"]
effort: 3
allowed-tools: Read, Glob, Grep
user-invocable: true
when_to_use: "When building or deploying serverless applications on AWS with Lambda, API Gateway, DynamoDB, or SAM/CDK"
---

# AWS Serverless

## Critical rules (non-obvious)

- **Initialize clients OUTSIDE handler** — Lambda reuses execution environments across invocations; creating clients inside costs 100-500ms per cold start
- **`context.callbackWaitsForEmptyEventLoop = false`** — prevents Node.js from hanging on open async handles (DB connections, etc.)
- **SQS `VisibilityTimeout` = 6× Lambda timeout** — if Lambda takes 30s, set 180s; otherwise messages return to queue mid-processing
- **`FunctionResponseTypes: [ReportBatchItemFailures]`** — partial batch failure; without this, any single failure retries the entire batch
- **Never use `*` in `Access-Control-Allow-Origin` with `credentials: true`** — browsers block it; use explicit origin

## Lambda handler pattern

```javascript
// Initialize once (reused across invocations = faster after cold start)
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, GetCommand } = require("@aws-sdk/lib-dynamodb");

const docClient = DynamoDBDocumentClient.from(new DynamoDBClient({}));

exports.handler = async (event, context) => {
  context.callbackWaitsForEmptyEventLoop = false;  // don't hang on open handles
  try {
    const body = typeof event.body === "string" ? JSON.parse(event.body) : event.body;
    const result = await docClient.send(new GetCommand({
      TableName: process.env.TABLE_NAME,
      Key: { id: body.id },
    }));
    return { statusCode: 200, headers: { "Content-Type": "application/json" }, body: JSON.stringify(result.Item) };
  } catch (err) {
    console.error(JSON.stringify({ error: err.message, requestId: context.awsRequestId }));
    return { statusCode: err.statusCode ?? 500, body: JSON.stringify({ error: err.message }) };
  }
};
```

## SAM template: HTTP API + DynamoDB

```yaml
# template.yaml
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:
  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      CorsConfiguration:
        AllowOrigins: ["https://yourdomain.com"]  # never * with credentials
        AllowMethods: [GET, POST, DELETE]
        AllowHeaders: ["*"]

  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

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

## SQS async processing with partial batch failure

```yaml
# In template.yaml
ProcessorFunction:
  Type: AWS::Serverless::Function
  Properties:
    Events:
      SQSEvent:
        Type: SQS
        Properties:
          Queue: !GetAtt ProcessingQueue.Arn
          BatchSize: 10
          FunctionResponseTypes:
            - ReportBatchItemFailures  # critical: retry only failed items

ProcessingQueue:
  Type: AWS::SQS::Queue
  Properties:
    VisibilityTimeout: 180  # 6x Lambda timeout (30s)
    RedrivePolicy:
      deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn
      maxReceiveCount: 3

DeadLetterQueue:
  Type: AWS::SQS::Queue
  Properties:
    MessageRetentionPeriod: 1209600  # 14 days
```

```javascript
// Handler with partial batch failure reporting
exports.handler = async (event) => {
  const batchItemFailures = [];
  for (const record of event.Records) {
    try {
      await processMessage(JSON.parse(record.body));
    } catch (err) {
      console.error(`Failed ${record.messageId}:`, err.message);
      batchItemFailures.push({ itemIdentifier: record.messageId });
    }
  }
  return { batchItemFailures };  // only failed items are retried
};
```

## Sharp edges

| Issue | Severity | Fix |
|---|---|---|
| Cold start > 1s | High | Move SDK init outside handler; use `--no-install-suggests` in Docker layers |
| Timeout without response | High | Always set explicit timeout < Lambda timeout in downstream calls |
| Memory = CPU allocation | High | 1792MB = 1 full vCPU; increase memory for CPU-bound tasks |
| VPC cold start adds 1-10s | Medium | Use VPC Endpoints instead of public NAT to reduce ENI setup |
| Infinite Lambda→SQS loop | High | Never write to same SQS queue that triggers Lambda without a dead-letter |
| S3 trigger infinite loop | High | Use separate source/destination buckets or prefix filters |

## Commands

```bash
sam build
sam local invoke GetItemFunction --event events/get-item.json
sam local start-api    # local API Gateway emulation
sam deploy --guided    # first deploy (creates samconfig.toml)
sam deploy             # subsequent deploys
```

More from tranhieutt/software_development_department

SkillDescription
agent-healthReads production/traces/agent-metrics.jsonl and displays a per-agent performance summary table for the current or a specified session. Highlights agents with high error rates or OPEN circuit breaker state.
agent-styleProvides the vendored agent-style v0.3.5 prose rule pack as a portable Claude skill. Use when installing, syncing, applying, or auditing SDD Agent-Style support in another project, or when a style-review workflow needs the bundled rules.
angular-best-practicesProvides Angular best practices for components, modules, services, and reactive patterns. Use when working with Angular TypeScript files, component templates, NgModules, RxJS observables, or when the user mentions Angular, ng, or Angular CLI.
annotateRecords unexpected API behaviors, undocumented caveats, version bugs, or non-obvious workarounds into .claude/memory/annotations.md. Use immediately when an undocumented behavior or surprising caveat is discovered during development.
backend-architectDesigns scalable backend architectures covering microservices, event-driven systems, API gateways, and data stores. Use when designing a backend system or when the user mentions backend architecture, scalability, or distributed systems.
cloud-run-puppeteerDeploys Puppeteer browser automation on Google Cloud Run with Docker. Use when running headless browser tasks on Cloud Run, or when the user mentions Cloud Run, Puppeteer, headless Chrome, or serverless browser automation.
codex-sddAdapts SDD for Codex while preserving Claude Code behavior. Use when working in Codex, setting up Codex compatibility, mapping Claude tools to Codex tools, or explaining how SDD should run outside Claude Code.
database-architectDesigns relational and NoSQL database schemas, indexing strategies, migration plans, and data modeling patterns. Use when designing a database or when the user mentions database architecture, schema design, or data modeling.
db-reviewReviews database schemas, queries, and migrations for correctness, performance, security, and best practices. Use when reviewing SQL migration files or when the user mentions database review, schema review, or query audit.
deep-interviewConducts a structured technical deep-dive to gather detailed requirements, constraints, and decisions from the user. Use when starting a complex feature or when the user wants to be asked structured clarifying questions before implementation.