Przejdź do głównej zawartości

Wzorce rozwoju serverless

Twoja Lambda przetwarzająca obrazy odpala się dwa razy na ten sam upload do S3, więc połowa miniatur zostaje zapisana, usunięta i zapisana ponownie — a CloudWatch to ściana nieustrukturyzowanych console.log, których nie da się powiązać z żadnym żądaniem. W międzyczasie p99 skacze co rano do 4 sekund przez cold starty, a „poprawka”, którą ktoś wdrożył (provisioned concurrency na każdej funkcji), podwoiła rachunek. Serverless usuwa serwery, a nie problemy systemów rozproszonych: ponowienia, idempotencja, cold starty i limity poszczególnych platform to teraz Twój kod.

Ten przepis pokazuje, jak sterować Cursor, Claude Code i Codex, by generowały kod serverless, który przetrwa te problemy — a nie demo na szczęśliwej ścieżce, które psuje się przy pierwszym ponownym dostarczeniu wiadomości przez SQS.

  • Gotowy prompt, który tworzy idempotentny handler AWS Lambda (deduplikacja przy ponowieniach) ze strukturalnym logowaniem do CloudWatch
  • Wzorzec API gateway na Cloudflare Workers z prawdziwym wrangler.toml oraz to, jak serwer MCP Cloudflare podgląda KV/R2/D1 bez wychodzenia z edytora
  • Workflow triage cold startów, który mówi, kiedy provisioned concurrency naprawdę jest warta swojej ceny
  • Podział na trzy narzędzia: kiedy używać agenta w Cursor, headless runs w Claude Code i Codex Cloud do PR-ów wdrożeniowych
  • Tryby awarii, które gryzą na produkcji — zduplikowane dostarczenia z SQS, hot partitions w DynamoDB, limity CPU w Workers — oraz prompty, które im zapobiegają

Krok 1: Zbuduj szkielet usługi (gdzie trzy narzędzia się różnią)

Dział zatytułowany „Krok 1: Zbuduj szkielet usługi (gdzie trzy narzędzia się różnią)”

Etap budowania szkieletu to moment, w którym ergonomia narzędzi rozjeżdża się najbardziej. Cursor edytuje pliki wizualnie w Twoim repozytorium; Claude Code uruchamia CLI frameworka z terminala i da się skryptować w CI; Codex potrafi rozdzielić to samo zadanie do worktree w chmurze i otworzyć PR wdrożeniowy. Wybieraj według tego, gdzie żyje praca, a nie według możliwości — wszystkie trzy sterują tymi samymi CLI: AWS SAM / Serverless Framework / Wrangler.

Otwórz tryb Agent (Cmd/Ctrl + I) w pustym repozytorium i daj mu jedną konkretną usługę do zbudowania:

Set up a Serverless Framework v4 service in TypeScript targeting AWS eu-central-1. One HTTP Lambda behind API Gateway (GET /health), one S3-triggered Lambda for image processing, and a DynamoDB table media (PK id). Use esbuild bundling, Node 22 runtime, and put stage/region in serverless.yml provider vars. Add a dev and prod stage.

Agent pisze serverless.yml, zaślepki handlerów i package.json. Przejrzyj diff w pasku bocznym przed zaakceptowaniem — Cursor zapisuje checkpoint przy każdej edycji, więc możesz cofnąć zły plik bez utraty reszty.

Krok 2: Uczyń handler idempotentnym (część, którą dema pomijają)

Dział zatytułowany „Krok 2: Uczyń handler idempotentnym (część, którą dema pomijają)”

S3, SQS i EventBridge dostarczają co najmniej raz. Naiwny handler przetwarza ten sam obiekt ponownie przy retry. Rozwiązaniem jest klucz deduplikacji — dla S3 to eTag obiektu — sprawdzany zapisem warunkowym przed wykonaniem pracy. To najcenniejsza rzecz, jaką możesz umieścić w prompcie, więc powiedz to wprost:

Ten prompt tworzy coś zbliżonego do tego — zwróć uwagę na wczesny return przy duplikacie i strukturalny log, bo to właśnie czyni kod możliwym do debugowania na produkcji:

// handler.ts — the AI-generated shape worth reviewing for
import { S3Event } from 'aws-lambda';
import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb';
const ddb = new DynamoDBClient({});
export const handler = async (event: S3Event) => {
const start = Date.now();
for (const rec of event.Records) {
const { bucket, object } = rec.s3;
const pk = `${bucket.name}/${object.key}#${object.eTag}`;
const log = { requestId: rec.responseElements['x-amz-request-id'], bucket: bucket.name, key: object.key, eTag: object.eTag };
try {
await ddb.send(new PutItemCommand({
TableName: process.env.DEDUPE_TABLE!,
Item: { pk: { S: pk } },
ConditionExpression: 'attribute_not_exists(pk)',
}));
} catch (err: any) {
if (err.name === 'ConditionalCheckFailedException') {
console.log(JSON.stringify({ ...log, status: 'duplicate-skipped' }));
continue; // already processed — S3 redelivery
}
throw err;
}
// ... resize with sharp, write derived/ objects ...
console.log(JSON.stringify({ ...log, status: 'ok', durationMs: Date.now() - start }));
}
};

To, co trzeba zweryfikować w wyniku AI: że zapis deduplikacyjny dzieje się przed efektami ubocznymi oraz że blok catch ponownie rzuca wyjątek (żeby DLQ faktycznie łapał awarie), zamiast go połykać.

Na Workers ograniczenia są inne — brak środowiska Node, budżet czasu CPU na żądanie i bindings zamiast klientów SDK. Poproś o gateway i konfigurację razem, żeby bindings w wrangler.toml pasowały do kodu:

# wrangler.toml — the AI should produce bindings that match the Worker
name = "api-gateway"
main = "src/index.ts"
compatibility_date = "2026-06-01"
[vars]
ORIGIN = "https://origin.internal.example.com"
[[kv_namespaces]]
binding = "TOKENS"
id = "<your-kv-id>"
[[durable_objects.bindings]]
name = "RATE_LIMITER"
class_name = "RateLimiter"
[[migrations]]
tag = "v1"
new_sqlite_classes = ["RateLimiter"]

Krok 4: Podgląd działającej infrastruktury serwerem MCP Cloudflare

Dział zatytułowany „Krok 4: Podgląd działającej infrastruktury serwerem MCP Cloudflare”

Wygenerowanie Workera to połowa roboty; błędy żyją w wartościach bindings — źle wpisane id namespace’u KV, nieaktualny wiersz w D1. Bez MCP przełączasz się alt-tabem między dashboardem a edytorem. Z zarządzanymi zdalnymi serwerami MCP Cloudflare AI czyta rzeczywisty stan Twojego konta oraz dokumentację w tej samej rozmowie. Konfiguracja jest identyczna we wszystkich trzech narzędziach — wskaż im zdalne endpointy (pełny katalog serwerów i przepływ OAuth w przewodniku Cloudflare MCP):

{
"mcpServers": {
"cloudflare-bindings": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://bindings.mcp.cloudflare.com/mcp"]
},
"cloudflare-observability": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://observability.mcp.cloudflare.com/mcp"]
}
}
}

Przed MCP debugowanie błędu nieaktualnego cache oznaczało kopiowanie id namespace’ów między czterema kartami przeglądarki. Po: „Read the TOKENS KV namespace bound to the api-gateway Worker and list the keys written in the last hour” i AI odpowiada na podstawie Twojego działającego konta. Do wdrożeń i edycji bindings z CLI lżejszą alternatywą jest skill Cloudflare wrangler — zainstaluj go poleceniem npx skills add cloudflare/skills/wrangler (z repozytorium cloudflare/skills, wymienionego na skills.sh). Skill lepiej pasuje, gdy chcesz tylko, by agent znał polecenia i konwencje wrangler; serwer MCP wygrywa, gdy potrzebujesz, by czytał stan na żywo.