Реалізація Serverless Event-Driven архітектури
Event-driven архітектура на serverless — це система, де компоненти спілкуються через события, а не прямі виклики. Lambda функція не знає, хто ще підписаний на результат її роботи. Це забезпечує слабку зв'язність, незалежне масштабування та можливість додавати нових споживачів без змін джерела.
Базові концепції
Event Source — джерело подій: API Gateway (HTTP запит), S3 (завантаження файлу), DynamoDB Streams (зміна запису), SQS (повідомлення в черзі), EventBridge (користувацька подія), Kinesis (потік даних).
Event Bridge (шина подій) — маршрутизатор подій. Джерело публікує подію, шина доставляє її потрібним споживачам за правилами.
Consumer (Lambda) — функція, що реагує на подію.
Архітектура на прикладі e-commerce
Обробка замовлення без event-driven: PlaceOrder → ValidateInventory → ProcessPayment → SendEmail → UpdateAnalytics — все послідовно, тісно пов'язано.
З event-driven:
[Client] → PlaceOrder Lambda
↓
EventBridge: order.created
/ | \
ValidateInv SendEmail Analytics
↓
EventBridge: inventory.reserved
↓
ProcessPayment
↓
EventBridge: payment.processed
/ \
FulfillOrder SendReceipt
Кожен сервіс реагує на события незалежно. Новий сервіс (наприклад, fraud detection) підписується на order.created без змін існуючого коду.
AWS EventBridge: реалізація
# Користувацька шина подій
resource "aws_cloudwatch_event_bus" "orders" {
name = "orders-bus"
}
# Правило маршрутизації
resource "aws_cloudwatch_event_rule" "order_created" {
name = "order-created"
event_bus_name = aws_cloudwatch_event_bus.orders.name
event_pattern = jsonencode({
"detail-type": ["OrderCreated"],
"source": ["com.company.orders"]
})
}
resource "aws_cloudwatch_event_target" "process_inventory" {
rule = aws_cloudwatch_event_rule.order_created.name
event_bus_name = aws_cloudwatch_event_bus.orders.name
arn = aws_lambda_function.validate_inventory.arn
}
resource "aws_cloudwatch_event_target" "send_confirmation" {
rule = aws_cloudwatch_event_rule.order_created.name
event_bus_name = aws_cloudwatch_event_bus.orders.name
arn = aws_lambda_function.send_email.arn
}
Публікація события з Lambda:
import boto3
import json
from datetime import datetime
events = boto3.client('events')
def publish_order_created(order: dict):
events.put_events(
Entries=[{
'EventBusName': 'orders-bus',
'Source': 'com.company.orders',
'DetailType': 'OrderCreated',
'Detail': json.dumps({
'orderId': order['id'],
'customerId': order['customer_id'],
'items': order['items'],
'totalAmount': order['total'],
'timestamp': datetime.utcnow().isoformat()
}),
'Time': datetime.utcnow()
}]
)
SQS для надійної доставки
EventBridge + SQS = відмовостійка доставка з retry та dead letter queue:
resource "aws_sqs_queue" "inventory_updates" {
name = "inventory-updates"
visibility_timeout_seconds = 300
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.inventory_dlq.arn
maxReceiveCount = 3 # Після 3 невдалих спроб → DLQ
})
}
resource "aws_lambda_event_source_mapping" "inventory_processor" {
event_source_arn = aws_sqs_queue.inventory_updates.arn
function_name = aws_lambda_function.process_inventory.arn
batch_size = 10
function_response_types = ["ReportBatchItemFailures"]
}
ReportBatchItemFailures — тільки невдалі повідомлення з batch повертаються в чергу, успішні не повторюються.
Обробник з partial failure
def handler(event, context):
failed_message_ids = []
for record in event['Records']:
try:
process_message(json.loads(record['body']))
except Exception as e:
# Тільки цей record йде в retry, інші — ОК
failed_message_ids.append({'itemIdentifier': record['messageId']})
return {'batchItemFailures': failed_message_ids}
Ідемпотентність
У event-driven системах события можуть доставляться двічі (at-least-once delivery). Кожен обробник повинен бути ідемпотентним:
import boto3
dynamodb = boto3.resource('dynamodb')
processed_events = dynamodb.Table('processed_events')
def handler(event, context):
for record in event['Records']:
event_id = record['messageId']
# Перевірити, чи не було обробленого события вже
try:
processed_events.put_item(
Item={'event_id': event_id, 'ttl': int(time.time()) + 86400},
ConditionExpression='attribute_not_exists(event_id)'
)
except processed_events.meta.client.exceptions.ConditionalCheckFailedException:
continue # Вже оброблено
process_event(record)
Моніторинг event-driven системи
Ключові метрики:
- Event lag (SQS ApproximateAgeOfOldestMessage) — наскільки свіжі события обробляються
- DLQ depth — число подій у dead letter queue (ненульове значення = проблема)
- Processing rate vs production rate — чи встигає система споживати события
- End-to-end latency — час від события до результату через весь ланцюг
Графік впровадження
- Проектування event schema + архітектури шини — 2-3 дні
- Налаштування EventBridge + правила маршрутизації — 2-3 дні
- SQS + DLQ + Lambda event sources — 2-3 дні
- Ідемпотентність обробників — 2-4 дні
- Distributed tracing + моніторинг — 2-3 дні
- Інтеграційне тестування — 2-4 дні







