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 不是。
  • 退避過長 — 睡過視窗的錯誤重試迴圈。

如何修正

  1. 捕捉它並從你最後的 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 跳到新活動。

  2. checkpoint sequence number,絕不 checkpoint iterator — sequence number 是持久的復原點。

  3. 保持輪詢迴圈緊湊 — 以非同步方式做繁重的逐記錄工作(將它排入佇列),讓 GetRecords 的節奏保持在 15 分鐘內。

  4. 偏好受管消費者 — Lambda event source mapping 與 DynamoDB Streams Kinesis Adapter(KCL)會為你管理 iterator 與 checkpoint;手工的 GetRecords 迴圈才是這個例外出沒之處。

確保你的處理是冪等的:從 checkpoint 復原可能重新遞送一個你處理到一半的記錄。stream 本身含有每個記錄恰好一次,但從其最後 checkpoint 重新播種的消費者實際上是至少一次的處理。

當你能看到項目變化時,除錯 stream 實際發出了什麼會容易得多 — DynoTable 桌面應用程式顯示項目的即時狀態,讓你能將 stream 記錄與資料對照。要估算追趕重播的讀取成本?DynamoDB 定價計算器幫你搞定。

相關錯誤

References

最後驗證於 2026-07-13,對照上方連結的 AWS 官方文件。

不必透過主控台就能操作 DynamoDB

DynoTable 是一款快速的 DynamoDB 桌面用戶端 — 瀏覽表格、執行 SQL 風格的查詢,並在本機編輯項目。