CDK Event Driven
AWS CDK Construct Event Driven Architecture EventBridge SQS Lambda Step Functions Serverless TypeScript Python Production
| Pattern | AWS Services | Use Case | CDK Construct Level |
|---|---|---|---|
| Fan-out | EventBridge → Lambda × N | Notify multiple services | L3 (Pattern) |
| Queue Processing | SQS → Lambda | Async job processing | L2 (SqsEventSource) |
| Saga | Step Functions | Distributed transactions | L3 (Custom) |
| CQRS | API GW + DynamoDB Stream | Separate read/write | L3 (Custom) |
| Event Sourcing | Kinesis + DynamoDB | Audit trail, replay | L3 (Custom) |
| DLQ | SQS DLQ + Lambda | Failed event handling | L2 (deadLetterQueue) |
CDK Constructs
# === CDK Event Driven Construct ===
# TypeScript CDK Example
# import * as cdk from 'aws-cdk-lib';
# import * as lambda from 'aws-cdk-lib/aws-lambda';
# import * as sqs from 'aws-cdk-lib/aws-sqs';
# import * as events from 'aws-cdk-lib/aws-events';
# import * as targets from 'aws-cdk-lib/aws-events-targets';
# import * as sources from 'aws-cdk-lib/aws-lambda-event-sources';
# import { Construct } from 'constructs';
#
# interface OrderProcessorProps {
# environment: string;
# maxConcurrency: number;
# retryAttempts: number;
# }
#
# class OrderProcessor extends Construct {
# public readonly queue: sqs.Queue;
# public readonly dlq: sqs.Queue;
# public readonly processor: lambda.Function;
#
# constructor(scope: Construct, id: string, props: OrderProcessorProps) {
# super(scope, id);
#
# // Dead Letter Queue
# this.dlq = new sqs.Queue(this, 'DLQ', {
# retentionPeriod: cdk.Duration.days(14),
# visibilityTimeout: cdk.Duration.seconds(300),
# });
#
# // Main Queue
# this.queue = new sqs.Queue(this, 'Queue', {
# visibilityTimeout: cdk.Duration.seconds(300),
# deadLetterQueue: {
# queue: this.dlq,
# maxReceiveCount: props.retryAttempts,
# },
# });
#
# // Lambda Processor
# this.processor = new lambda.Function(this, 'Fn', {
# runtime: lambda.Runtime.NODEJS_20_X,
# handler: 'index.handler',
# code: lambda.Code.fromAsset('lambda/order-processor'),
# timeout: cdk.Duration.seconds(60),
# memorySize: 512,
# reservedConcurrentExecutions: props.maxConcurrency,
# environment: { ENV: props.environment, QUEUE_URL: this.queue.queueUrl },
# });
#
# // Connect SQS → Lambda
# this.processor.addEventSource(new sources.SqsEventSource(this.queue, {
# batchSize: 10,
# maxBatchingWindow: cdk.Duration.seconds(5),
# }));
#
# // EventBridge Rule → SQS
# new events.Rule(this, 'OrderRule', {
# eventPattern: { source: ['com.myapp.orders'], detailType: ['OrderCreated'] },
# targets: [new targets.SqsQueue(this.queue)],
# });
# }
# }
from dataclasses import dataclass
@dataclass
class ConstructLevel:
level: str
name: str
description: str
example: str
when_to_use: str
levels = [
ConstructLevel("L1", "CFN Resources",
"CloudFormation Resource ตรงๆ ตั้งทุก Property เอง",
"CfnBucket, CfnFunction, CfnQueue",
"ต้องการ Control ทุก Property ไม่มี L2 สำหรับ Service นั้น"),
ConstructLevel("L2", "AWS Constructs",
"Higher-level มี Default ที่ดี Grant Permission ง่าย",
"s3.Bucket, lambda.Function, sqs.Queue",
"ใช้บ่อยที่สุด 90% ของงาน Default ดี ปรับได้"),
ConstructLevel("L3", "Patterns",
"รวมหลาย L2 เข้าด้วยกัน เป็น Solution Pattern",
"LambdaRestApi, QueueProcessingFargateService",
"Pattern ซ้ำๆ สร้างเป็น Reusable Construct"),
]
print("=== CDK Construct Levels ===")
for l in levels:
print(f" [{l.level}] {l.name}")
print(f" Description: {l.description}")
print(f" Example: {l.example}")
print(f" When: {l.when_to_use}")
Event Patterns
# === Event Driven Patterns ===
# Fan-out with EventBridge
# const bus = new events.EventBus(this, 'AppBus');
#
# // Rule 1: Order → Inventory Lambda
# new events.Rule(this, 'InventoryRule', {
# eventBus: bus,
# eventPattern: { detailType: ['OrderCreated'] },
# targets: [new targets.LambdaFunction(inventoryFn)],
# });
#
# // Rule 2: Order → Notification Lambda
# new events.Rule(this, 'NotifyRule', {
# eventBus: bus,
# eventPattern: { detailType: ['OrderCreated'] },
# targets: [new targets.LambdaFunction(notifyFn)],
# });
#
# // Rule 3: Order → Analytics SQS
# new events.Rule(this, 'AnalyticsRule', {
# eventBus: bus,
# eventPattern: { detailType: ['OrderCreated'] },
# targets: [new targets.SqsQueue(analyticsQueue)],
# });
@dataclass
class EventPattern:
pattern: str
services: str
flow: str
benefit: str
cdk_construct: str
patterns = [
EventPattern("Fan-out",
"EventBridge → Lambda/SQS/SNS × N",
"1 Event → หลาย Consumer พร้อมกัน",
"Loose coupling เพิ่ม Consumer ไม่กระทบ Producer",
"events.Rule + targets.LambdaFunction/SqsQueue"),
EventPattern("Queue Processing",
"SQS → Lambda (Event Source Mapping)",
"Producer → SQS Queue → Lambda Poll → Process",
"Buffer load spikes, Retry, DLQ, Batch processing",
"sqs.Queue + lambda.Function + SqsEventSource"),
EventPattern("Saga (Orchestration)",
"Step Functions → Lambda × N",
"Step Function ควบคุม Flow: Pay → Ship → Notify",
"Transaction management, Compensation, Visibility",
"stepfunctions.StateMachine + tasks.LambdaInvoke"),
EventPattern("CQRS",
"API GW → Lambda → DynamoDB → Stream → Lambda → Read DB",
"Write ผ่าน Command API, Read ผ่าน Query API แยกกัน",
"Scale Read/Write แยก Optimize แต่ละด้าน",
"apigateway.RestApi + dynamodb.Table + DynamoEventSource"),
EventPattern("Dead Letter Queue",
"SQS Main Queue → DLQ after N retries",
"Failed messages ไป DLQ → Lambda/Dashboard วิเคราะห์",
"ไม่สูญเสีย Event ที่ Fail วิเคราะห์ Root Cause ได้",
"sqs.Queue({ deadLetterQueue: { queue, maxReceiveCount } })"),
]
print("=== Event Patterns ===")
for p in patterns:
print(f" [{p.pattern}] {p.services}")
print(f" Flow: {p.flow}")
print(f" Benefit: {p.benefit}")
print(f" CDK: {p.cdk_construct}")
Testing
# === CDK Testing ===
# import { Template, Match } from 'aws-cdk-lib/assertions';
# import { App } from 'aws-cdk-lib';
# import { OrderProcessorStack } from '../lib/order-processor-stack';
#
# test('Queue created with DLQ', () => {
# const app = new App();
# const stack = new OrderProcessorStack(app, 'Test');
# const template = Template.fromStack(stack);
#
# template.hasResourceProperties('AWS::SQS::Queue', {
# RedrivePolicy: Match.objectLike({
# maxReceiveCount: 3,
# }),
# });
# });
#
# test('Lambda has correct timeout', () => {
# template.hasResourceProperties('AWS::Lambda::Function', {
# Timeout: 60,
# MemorySize: 512,
# });
# });
#
# test('EventBridge rule targets queue', () => {
# template.hasResourceProperties('AWS::Events::Rule', {
# EventPattern: Match.objectLike({
# 'detail-type': ['OrderCreated'],
# }),
# });
# });
@dataclass
class TestType:
test: str
tool: str
what: str
example: str
tests = [
TestType("Snapshot Test",
"CDK Assertions Template.fromStack",
"ตรวจ Template ไม่เปลี่ยนจากที่คาดหวัง",
"expect(template.toJSON()).toMatchSnapshot()"),
TestType("Fine-grained Assertion",
"template.hasResourceProperties",
"ตรวจ Resource มี Property ที่ถูกต้อง",
"hasResourceProperties('AWS::SQS::Queue', {...})"),
TestType("Resource Count",
"template.resourceCountIs",
"ตรวจจำนวน Resource ที่สร้าง",
"resourceCountIs('AWS::Lambda::Function', 3)"),
TestType("cdk-nag",
"cdk-nag NagPacks",
"ตรวจ Security Compliance Best Practices",
"Aspects.of(app).add(new AwsSolutionsChecks())"),
TestType("Integration Test",
"AWS SDK + deployed stack",
"ทดสอบ Event Flow จริงบน AWS",
"Put event → Check Lambda executed → Verify output"),
]
print("=== CDK Testing ===")
for t in tests:
print(f" [{t.test}] Tool: {t.tool}")
print(f" What: {t.what}")
print(f" Example: {t.example}")
เคล็ดลับ
- L2: ใช้ L2 Construct เป็นหลัก Default ดี Grant Permission ง่าย
- DLQ: ทุก Queue ต้องมี DLQ ไม่มีข้อยกเว้น ป้องกัน Event หาย
- EventBridge: ใช้ EventBridge เป็น Central Event Router ไม่ใช่ SNS
- Test: เขียน CDK Assertion Test + cdk-nag ทุก Stack
- Reuse: สร้าง L3 Construct สำหรับ Pattern ที่ใช้ซ้ำ Publish npm
AWS CDK คืออะไร
IaC Framework TypeScript Python Java Construct L1 L2 L3 CloudFormation AWS Service CDK CLI Deploy synth diff Reusable npm
Event Driven Design คืออะไร
Event Producer Router Consumer Loose Coupling EventBridge SQS SNS Lambda Step Functions Kinesis Scale Retry DLQ Failure Tolerance
สร้าง Construct อย่างไร
Class Extend Construct Props Interface Lambda SQS EventBridge Grant Permission addTarget Export Output Aspects Tagging cdk-nag npm Publish
Production Patterns มีอะไร
Fan-out EventBridge Queue SQS Lambda Saga Step Functions CQRS DynamoDB Stream DLQ Event Sourcing Kinesis Circuit Breaker Retry
สรุป
AWS CDK Construct Event Driven EventBridge SQS Lambda Step Functions Fan-out Saga CQRS DLQ L2 L3 Pattern Testing Production
