Skip to content

Event-Driven Fan-Out (CDK)

Source: examples/event-driven-fanout.yaml

To check and price this model from a clone of the repository:

infra-cost-model validate examples/event-driven-fanout.yaml
infra-cost-model compute --time-basis monthly examples/event-driven-fanout.yaml
# Example: Event-Driven Fan-Out (CDK)
# Demonstrates: SNS fan-out to multiple SQS queues with different call rates,
# multi-path DAG accumulation via Kahn's algorithm, long-running compute,
# data volume metrics.
#
# Issue: https://github.com/elecnix/infra-cost-model/issues/5

version: "1.0"

workflow:
  name: event-driven-orders
  entry: aws_apigatewayv2_api.orders_api
  frequency:
    unit: perMinute
    value: 500

nodes:
  aws_apigatewayv2_api.orders_api:
    nodeType: routing
    resourceAddress: aws_apigatewayv2_api.orders_api
    provider: aws
    region: us-east-1
    service: AmazonAPIGatewayHTTP
    usageMetrics:
      requests: { unit: requests, value: 1 }

  # An HTTP API has no egress price of its own. AWS bills the response bytes
  # as data transfer out to the internet.
  data_transfer.orders_api_egress:
    nodeType: external
    resourceAddress: data_transfer.orders_api_egress
    provider: aws
    region: us-east-1
    service: AWSDataTransfer
    usageMetrics:
      internetOutGb: { unit: GB, value: 0.00001 }    # 10KB per request

  aws_lambda_function.producer:
    nodeType: compute
    resourceAddress: aws_lambda_function.producer
    provider: aws
    region: us-east-1
    service: AWSLambda
    usageMetrics:
      invocations: { unit: requests, value: 1 }
      avgDurationMs: { unit: ms, value: 100 }
      memoryMb: { unit: MB, value: 256 }

  aws_sns_topic.order_events:
    nodeType: routing
    resourceAddress: aws_sns_topic.order_events
    provider: aws
    region: us-east-1
    service: AmazonSNS
    usageMetrics:
      publishes: { unit: requests, value: 1 }

  aws_sqs_queue.orders_queue:
    nodeType: routing
    resourceAddress: aws_sqs_queue.orders_queue
    provider: aws
    region: us-east-1
    service: AmazonSQS
    usageMetrics:
      messagesSent: { unit: requests, value: 1 }

  aws_sqs_queue.notifications_queue:
    nodeType: routing
    resourceAddress: aws_sqs_queue.notifications_queue
    provider: aws
    region: us-east-1
    service: AmazonSQS
    usageMetrics:
      messagesSent: { unit: requests, value: 1 }

  aws_sqs_queue.analytics_queue:
    nodeType: routing
    resourceAddress: aws_sqs_queue.analytics_queue
    provider: aws
    region: us-east-1
    service: AmazonSQS
    usageMetrics:
      messagesSent: { unit: requests, value: 1 }

  aws_lambda_function.order_processor:
    nodeType: compute
    resourceAddress: aws_lambda_function.order_processor
    provider: aws
    region: us-east-1
    service: AWSLambda
    usageMetrics:
      invocations: { unit: requests, value: 1 }
      avgDurationMs: { unit: ms, value: 300 }
      memoryMb: { unit: MB, value: 512 }

  aws_lambda_function.notifier:
    nodeType: compute
    resourceAddress: aws_lambda_function.notifier
    provider: aws
    region: us-east-1
    service: AWSLambda
    usageMetrics:
      invocations: { unit: requests, value: 1 }
      avgDurationMs: { unit: ms, value: 50 }
      memoryMb: { unit: MB, value: 256 }

  aws_lambda_function.analyzer:
    nodeType: compute
    resourceAddress: aws_lambda_function.analyzer
    provider: aws
    region: us-east-1
    service: AWSLambda
    usageMetrics:
      invocations: { unit: requests, value: 1 }
      avgDurationMs: { unit: ms, value: 5000 }
      memoryMb: { unit: MB, value: 1024 }

  aws_dynamodb_table.orders:
    nodeType: storage
    resourceAddress: aws_dynamodb_table.orders
    provider: aws
    region: us-east-1
    service: AmazonDynamoDB
    usageMetrics:
      # One write per call. The edge from order_processor carries rate 2.
      writeRequests: { unit: requests, value: 1 }

  aws_sns_topic.alerts:
    nodeType: routing
    resourceAddress: aws_sns_topic.alerts
    provider: aws
    region: us-east-1
    service: AmazonSNS
    usageMetrics:
      publishes: { unit: requests, value: 1 }

  aws_s3_bucket.data_lake:
    nodeType: storage
    resourceAddress: aws_s3_bucket.data_lake
    provider: aws
    region: us-east-1
    service: AmazonS3
    usageMetrics:
      putRequests: { unit: requests, value: 1 }

edges:
  # Every response leaves AWS as data transfer out
  - from: aws_apigatewayv2_api.orders_api
    to: data_transfer.orders_api_egress
    rate: 1

  # Entry: API Gateway → Producer Lambda
  - from: aws_apigatewayv2_api.orders_api
    to: aws_lambda_function.producer
    rate: 1

  # Producer → SNS (fan-out source)
  - from: aws_lambda_function.producer
    to: aws_sns_topic.order_events
    rate: 1

  # SNS fan-out to 3 SQS queues with different call rates
  - from: aws_sns_topic.order_events
    to: aws_sqs_queue.orders_queue
    rate: 0.8              # 80% are order events
  - from: aws_sns_topic.order_events
    to: aws_sqs_queue.notifications_queue
    rate: 1.0              # 100% get notifications
  - from: aws_sns_topic.order_events
    to: aws_sqs_queue.analytics_queue
    rate: 0.5              # 50% sampled for analytics

  # Orders path: SQS → order_processor → DynamoDB
  - from: aws_sqs_queue.orders_queue
    to: aws_lambda_function.order_processor
    rate: 1
  - from: aws_lambda_function.order_processor
    to: aws_dynamodb_table.orders
    rate: 2
    type: write

  # Notifications path: SQS → notifier → SNS alerts
  - from: aws_sqs_queue.notifications_queue
    to: aws_lambda_function.notifier
    rate: 1
  - from: aws_lambda_function.notifier
    to: aws_sns_topic.alerts
    rate: 1

  # Analytics path: SQS → analyzer → S3
  - from: aws_sqs_queue.analytics_queue
    to: aws_lambda_function.analyzer
    rate: 1
  - from: aws_lambda_function.analyzer
    to: aws_s3_bucket.data_lake
    rate: 1
    dataSize:
      unit: kB
      average: 500              # 500KB per analytics event