1.3 Event-Driven Streaming Ingestion with DynamoDB Streams & Lambda

Key Takeaways

  • DynamoDB Streams captures time-ordered sequences of item-level modifications (INSERT, MODIFY, REMOVE) with 24-hour strictly ordered retention per partition key, enabling asynchronous Change Data Capture (CDC).
  • Kinesis Data Streams for DynamoDB extends retention up to 365 days and supports additional fan-out consumers and Amazon Data Firehose delivery without consuming DynamoDB table read capacity units.
  • AWS Lambda Event Source Mapping (ESM) reads streams using polling threads, supporting batch sizes (1 to 10,000 records), batch windowing (up to 300s), parallelization factor (up to 10 concurrent Lambda invocations per shard), and bisect-on-function-error.
  • Idempotent processing using unique message identifiers or DynamoDB conditional writes prevents duplicate side-effects caused by Lambda retries during stream processing failures.
Last updated: August 2026

1.3 Event-Driven Streaming Ingestion with DynamoDB Streams & Lambda

Change Data Capture (CDC) Architecture

In event-driven cloud architectures, capturing database modifications as a real-time event stream is known as Change Data Capture (CDC). CDC enables downstream decoupled architectures—such as invalidating caches, updating search indexes in OpenSearch, updating data warehouse tables, or triggering serverless workflows—without performing expensive periodic database polling.

AWS provides native CDC capabilities for Amazon DynamoDB through two streaming integrations: DynamoDB Streams and Amazon Kinesis Data Streams for DynamoDB.


DynamoDB Streams Fundamentals

DynamoDB Streams captures a time-ordered sequence of item-level modifications (INSERT, MODIFY, REMOVE) occurring within a DynamoDB table. The log entries are written asynchronously to the stream within milliseconds of the database update.

Key Characteristics of DynamoDB Streams

  • Ordering & Scope: Record modification events are strictly ordered per item primary key. Events for distinct items may arrive in arbitrary order.
  • Shard Lifecycle: Stream records are organized into shards, which represent a log of table modifications. Shards auto-split and merge in tandem with underlying DynamoDB physical partition scaling.
  • 24-Hour Fixed Retention: Stream records are retained for exactly 24 hours. Data older than 24 hours is automatically trimmed and permanently lost. Retention period is non-configurable.
  • Zero Impact on Read Capacity: Polling or reading records from DynamoDB Streams does NOT consume table Read Capacity Units (RCUs).

Stream View Types

When enabling DynamoDB Streams, you must specify the Stream View Type, which defines what information is captured in each stream record:

Stream View TypeContent Included in Event PayloadUse Case
KEYS_ONLYOnly the key attributes of the modified itemTriggering lightweight cache invalidation
NEW_IMAGEThe entire item as it appears after modificationForwarding new state to downstream analytical sinks
OLD_IMAGEThe entire item as it appeared before modificationAuditing deleted records or state cleanups
NEW_AND_OLD_IMAGESBoth the new and old item state imagesCalculating state diffs, operational metrics, or audit logs

Kinesis Data Streams Integration for DynamoDB

For advanced analytics pipelines, AWS allows streaming DynamoDB table changes directly into Amazon Kinesis Data Streams instead of standard DynamoDB Streams.

Architectural Comparison: DynamoDB Streams vs. Kinesis Data Streams

Feature / LimitNative DynamoDB StreamsKinesis Data Streams for DynamoDB
Data RetentionFixed 24 hours (non-extendable)Up to 365 days (8,760 hours)
Max Concurrent Readers2 readers per shard maxUp to 20 readers per shard with Enhanced Fan-Out (EFO)
Delivery SinksCustom consumers (AWS Lambda, KCL)Direct delivery to S3/Redshift via Amazon Data Firehose
Pricing ModelNo charge to enable the stream or call its read API; downstream consumers can have separate chargesPay for Kinesis capacity and payload processing
Multi-Region ReplicationUsed internally by DynamoDB Global TablesRegional stream; cross-account or cross-Region delivery requires an explicit architecture

Decision Guidance: Choose native DynamoDB Streams for lightweight, low-cost Lambda triggers requiring <24h retention. Choose Kinesis Data Streams for DynamoDB when requiring retention >24h, fan-out to >2 consumers, or direct ingestion into Amazon S3 via Firehose.


AWS Lambda Event Source Mapping (ESM)

AWS Lambda integrates with streaming sources (DynamoDB Streams, Kinesis, MSK) via an internal infrastructure component called the Event Source Mapping (ESM). The ESM runs a polling loop on behalf of your serverless architecture, fetching batches of records from stream shards and invoking your Lambda function synchronously.

Tuning ESM Batching & Concurrency

  1. Batch Size (BatchSize): Configures the maximum number of records (1 to 10,000) passed to a single Lambda invocation.
  2. Maximum Batching Window (MaximumBatchingWindowInSeconds): Sets the maximum time (0 to 300 seconds) Lambda waits to gather records before invoking the function. If BatchSize is not met, Lambda invokes the function as soon as the window expires.
  3. Parallelization Factor (ParallelizationFactor): By default, Lambda processes each stream shard with 1 concurrent invocation to guarantee ordered processing. Setting ParallelizationFactor (from 1 to 10) divides a single shard into concurrent sub-streams grouped by partition key, allowing up to 10 concurrent Lambda invocations per shard while preserving strict partition key ordering!

Resilient Error Handling & Dead Letter Destinations

When a Lambda function throws an unhandled exception while processing a stream batch, the ESM halts shard processing and retries the entire batch repeatedly until records expire (24 hours). This causes a blocked shard (poison pill block).

To prevent shard blocking, configure advanced ESM error controls:

  • BisectBatchOnFunctionError: When set to True, if a batch invocation fails, Lambda automatically splits the failing record batch into two smaller sub-batches and retries them separately. It recursively bisects until the exact failing record is isolated.
  • MaximumRetryAttempts & MaximumRecordAgeInSeconds: Limits how many times Lambda retries a failing record batch or drops records older than a set threshold.
  • On-Failure Destination (DestinationOnFailure): Automatically routes metadata about dropped or failed records directly to an Amazon SQS queue or Amazon SNS topic for offline inspection and replay.

Idempotent Stream Processing Patterns

Because stream processing guarantees at-least-once delivery, network retries or Lambda function re-invocations can deliver the same stream event multiple times. Lambda functions MUST be designed to be idempotent (processing the same event multiple times produces the exact same side-effect).

Idempotency Techniques

  1. Deterministic Unique Keys: Use the DynamoDB Streams eventID or business transaction ID as an idempotency key.
  2. DynamoDB Conditional Writes: Maintain a dedicated tracking table in DynamoDB. Before processing, insert the eventID using a conditional expression: attribute_not_exists(event_id) If the insert succeeds, process the payload. If a ConditionalCheckFailedException is raised, skip processing as it is a duplicate event.

Code Example: Idempotent Python Lambda Handler for DynamoDB CDC

import json
import os
import time
import boto3
from botocore.exceptions import ClientError

dynamodb = boto3.resource('dynamodb')
PROCESSED_EVENTS_TABLE = os.environ.get('PROCESSED_EVENTS_TABLE', 'ProcessedStreamEvents')
table = dynamodb.Table(PROCESSED_EVENTS_TABLE)

def lambda_handler(event, context):
    records = event.get('Records', [])
    print(f"Processing batch of {len(records)} DynamoDB stream records.")
    
    for record in records:
        event_id = record['eventID']
        event_name = record['eventName']  # INSERT, MODIFY, REMOVE
        
        # Attempt idempotent registration
        try:
            table.put_item(
                Item={'event_id': event_id, 'ttl': int(time.time()) + 86400},
                ConditionExpression='attribute_not_exists(event_id)'
            )
        except ClientError as e:
            if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
                print(f"Duplicate event detected: {event_id}. Skipping execution.")
                continue
            raise e
            
        # Parse CDC Image Payload
        ddb_data = record.get('dynamodb', {})
        new_image = ddb_data.get('NewImage', {})
        old_image = ddb_data.get('OldImage', {})
        
        print(f"Executing CDC event {event_name} for ID {event_id}")
        # Perform downstream integration logic here (e.g. forward to S3/OpenSearch)
        
    return {"statusCode": 200, "body": json.dumps("Stream processing batch completed.")}
Loading diagram...
DynamoDB Streams & AWS Lambda ESM Architecture with Error Handling
Test Your Knowledge

An AWS Lambda function processing a DynamoDB Stream batch fails repeatedly due to a single corrupt record ('poison pill'), causing stream processing on that shard to stall indefinitely. How can a data engineer configure the Lambda Event Source Mapping to automatically isolate corrupt records without losing data or blocking shard throughput?

A
B
C
D
Test Your Knowledge

A data architecture requires streaming all table modifications from a high-throughput DynamoDB table directly into Amazon S3 for long-term compliance storage (up to 1 year). The stream must be consumed by 5 separate analytics systems without consuming DynamoDB Read Capacity Units (RCUs). Which configuration meets these requirements?

A
B
C
D
Test Your Knowledge

A data engineering team is building a Change Data Capture (CDC) audit system that requires comparing the exact attribute values of a DynamoDB item BEFORE and AFTER a modification. Which DynamoDB Stream View Type MUST be selected when enabling the stream?

A
B
C
D