Розроблення Serverless Functions для сайту (AWS Lambda)
AWS Lambda — функції, що запускаються по події й не потребують постійно запущеного сервера. Платіть тільки за фактичний час виконання: перші 1M запитів на місяць безплатно, далі $0.20 за 1M запитів. Cold start — єдиний серйозний недолік, вирішуваний кількома способами.
Коли Lambda підходить для сайту
Підходить: обробка контактних форм, генерація PDF/зображень за запитом, вебхуки від платіжних систем та CRM, ресайз зображень при завантаженні, планувальники задач (cron через EventBridge), API-проксі для сторонніх сервісів.
Не підходить: довгоживучі з'єднання (WebSocket потребує окремого сервісу), задачі > 15 хвилин, високочастотні операції з БД без connection pooling.
Структура проекту
my-lambda/
├── src/
│ ├── handlers/
│ │ ├── contact-form.ts
│ │ ├── image-resize.ts
│ │ └── webhook.ts
│ ├── services/
│ │ ├── email.ts
│ │ └── storage.ts
│ └── utils/
├── template.yaml # SAM або serverless.yml
├── package.json
└── tsconfig.json
Приклад функції: обробка контактної форми
import { APIGatewayProxyHandler } from "aws-lambda";
import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses";
import { z } from "zod";
const ses = new SESClient({ region: "eu-west-1" });
const ContactSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
message: z.string().min(10).max(2000),
});
export const handler: APIGatewayProxyHandler = async (event) => {
const headers = {
"Access-Control-Allow-Origin": "https://your-site.com",
"Content-Type": "application/json",
};
try {
const body = JSON.parse(event.body || "{}");
const data = ContactSchema.parse(body);
await ses.send(new SendEmailCommand({
Source: "[email protected]",
Destination: { ToAddresses: ["[email protected]"] },
Message: {
Subject: { Data: `Нове повідомлення від ${data.name}` },
Body: {
Text: { Data: `Від: ${data.name} <${data.email}>\n\n${data.message}` }
}
}
}));
return { statusCode: 200, headers, body: JSON.stringify({ ok: true }) };
} catch (error) {
if (error instanceof z.ZodError) {
return { statusCode: 400, headers, body: JSON.stringify({ errors: error.errors }) };
}
console.error(error);
return { statusCode: 500, headers, body: JSON.stringify({ error: "Internal error" }) };
}
};
Деплой через AWS SAM
template.yaml:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs20.x
Timeout: 10
MemorySize: 256
Environment:
Variables:
NODE_ENV: production
Resources:
ContactFormFunction:
Type: AWS::Serverless::Function
Properties:
Handler: dist/handlers/contact-form.handler
Events:
Api:
Type: HttpApi
Properties:
Path: /contact
Method: POST
Policies:
- SESCrudPolicy:
IdentityName: your-site.com
npm run build
sam build
sam deploy --guided # перший деплой
sam deploy # подальші
Cold start та його усунення
Cold start на Node.js 20 — 200–500 мс. На Python — 100–300 мс. Після першого виклику функція залишається "гарячою" кілька хвилин.
Способи зниження:
- Provisioned Concurrency — Lambda утримує N екземплярів завжди гарячими. Коштує ~$0.015 за годину на екземпляр. Для критичних endpoints з SLA.
-
Зменшення розміру бандла — використовуйте esbuild замість webpack, не включайте
aws-sdkв бандл (він уже в середовищі), tree-shaking. - SnapStart (Java) — снімок стану після ініціалізації.
- Pingер — EventBridge раз на 5 хвилин викликає функцію з warmup-payload.
// Ініціалізація поза handler — виконується один раз при cold start
const dbClient = new DynamoDBClient({ region: "eu-west-1" });
const sesClient = new SESClient({ region: "eu-west-1" });
export const handler = async (event) => {
// handler використовує вже ініціалізовані клієнти
};
Робота з базою даних
Стандартне TCP-з'єднання до PostgreSQL/MySQL не підходить для Lambda — кожен виклик створює нове з'єднання, при 1000 RPS база захлебується.
Рішення:
- RDS Proxy — connection pooler перед RDS, Lambda підключається до проксі. +$0.015 за vCPU/час RDS.
- DynamoDB — немає з'єднань, нативно serverless. Для простих структур даних.
- PlanetScale / Neon — serverless-сумісні бази з HTTP API.
Логування та трейсинг
import { Logger } from "@aws-lambda-powertools/logger";
import { Tracer } from "@aws-lambda-powertools/tracer";
const logger = new Logger({ serviceName: "contact-form" });
const tracer = new Tracer({ serviceName: "contact-form" });
export const handler = tracer.captureLambdaHandler(async (event) => {
logger.addContext(context);
logger.info("Processing contact form", { email: event.body?.email });
// ...
});
AWS Lambda Powertools — офіційна бібліотека для структурованого логування, трейсингу через X-Ray, метрик через CloudWatch EMF.
Графік
Одна Lambda-функція з деплоєм через SAM — 1–2 дні. Набір з 5–7 функцій з CI/CD через GitHub Actions та моніторингом — 5–7 днів.







