Technology

CDK Construct Event Driven Design

cdk construct event driven design
CDK Construct Event Driven Design | SiamCafe Blog
2025-12-25· อ. บอม — SiamCafe.net· 11,508 คำ

CDK Event Driven

AWS CDK Construct Event Driven Architecture EventBridge SQS Lambda Step Functions Serverless TypeScript Python Production

PatternAWS ServicesUse CaseCDK Construct Level
Fan-outEventBridge → Lambda × NNotify multiple servicesL3 (Pattern)
Queue ProcessingSQS → LambdaAsync job processingL2 (SqsEventSource)
SagaStep FunctionsDistributed transactionsL3 (Custom)
CQRSAPI GW + DynamoDB StreamSeparate read/writeL3 (Custom)
Event SourcingKinesis + DynamoDBAudit trail, replayL3 (Custom)
DLQSQS DLQ + LambdaFailed event handlingL2 (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}")

เคล็ดลับ

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

📖 บทความที่เกี่ยวข้อง

oVirt Virtualization Event Driven Designอ่านบทความ → CDK Construct API Gateway Patternอ่านบทความ → Healthchecks.io Domain Driven Design DDDอ่านบทความ → CDK Construct Kubernetes Deploymentอ่านบทความ → CDK Construct Cloud Migration Strategyอ่านบทความ →

📚 ดูบทความทั้งหมด →