DynamoDB Streams: ExpiredIteratorException
TL;DR — 來自 GetShardIterator 的 shard iterator 只有 15 分鐘的有效期。若你的消費者暫停、緩慢地處理批次,或跨越重新啟動持有 iterator,下一個 GetRecords 呼叫就會拋出這個錯誤。以請求新的 iterator 復原 — 使用 AFTER_SEQUENCE_NUMBER 搭配你最後處理的 sequence number,讓你精確地從中斷處繼續。
這是什麼意思
ExpiredIteratorException: The provided iterator exceeds the maximum age allowed.直接讀取 DynamoDB stream 是一個兩步驟迴圈:GetShardIterator 給你一個進入 shard 的位置控制代碼,而每個 GetRecords 呼叫會消耗它並回傳下一個(NextShardIterator)。每一個這種控制代碼在發出後 15 分鐘過期。這個例外不代表資料消失了 — stream 記錄存活 24 小時 — 它只代表這個_位置控制代碼_過時了,你需要一個新的。
為什麼會發生
- 輪詢之間處理緩慢 — 每個批次做的工作(寫入、外部呼叫)在下一個
GetRecords之前花了超過 15 分鐘。 - 暫停或掛起的消費者 — 停止的 worker、漫長的部署,或持有迴圈的除錯器工作階段。
- 儲存 iterator — 將 iterator 字串持久化(在 DB 或 checkpoint 中)並稍後重用;iterator 是短暫的,sequence number 不是。
- 退避過長 — 睡過視窗的錯誤重試迴圈。
如何修正
捕捉它並從你最後的 checkpoint 重新播種 iterator — 追蹤你最後處理記錄的
SequenceNumber,然後:const {ShardIterator} = await streams.send( new GetShardIteratorCommand({ StreamArn: streamArn, ShardId: shardId, ShardIteratorType: 'AFTER_SEQUENCE_NUMBER', SequenceNumber: lastProcessedSequenceNumber }) );還沒有 checkpoint?
TRIM_HORIZON從最舊的可用記錄重新處理 shard;LATEST跳到新活動。checkpoint sequence number,絕不 checkpoint iterator — sequence number 是持久的復原點。
保持輪詢迴圈緊湊 — 以非同步方式做繁重的逐記錄工作(將它排入佇列),讓
GetRecords的節奏保持在 15 分鐘內。偏好受管消費者 — Lambda event source mapping 與 DynamoDB Streams Kinesis Adapter(KCL)會為你管理 iterator 與 checkpoint;手工的
GetRecords迴圈才是這個例外出沒之處。
確保你的處理是冪等的:從 checkpoint 復原可能重新遞送一個你處理到一半的記錄。stream 本身含有每個記錄恰好一次,但從其最後 checkpoint 重新播種的消費者實際上是至少一次的處理。
當你能看到項目變化時,除錯 stream 實際發出了什麼會容易得多 — DynoTable 桌面應用程式顯示項目的即時狀態,讓你能將 stream 記錄與資料對照。要估算追趕重播的讀取成本?DynamoDB 定價計算器幫你搞定。
相關錯誤
- TrimmedDataAccessException — 你落後於 24 小時的保留視窗(資料確實消失了)。
- Stream not enabled
- Invalid StreamArn
- 學習:DynamoDB Streams
References
- GetShardIterator — Amazon DynamoDB Streams API Reference
- GetRecords — Amazon DynamoDB Streams API Reference
- Change data capture for DynamoDB Streams — Amazon DynamoDB Developer Guide
最後驗證於 2026-07-13,對照上方連結的 AWS 官方文件。