DynamoDB Streams: ExpiredIteratorException

요약 — GetShardIterator의 샤드 이터레이터는 15분 동안만 유효합니다. 소비자가 일시 중지했거나, 배치를 느리게 처리했거나, 재시작 간 이터레이터를 붙잡고 있었다면 다음 GetRecords 호출이 이것을 던집니다. 새 이터레이터를 요청해 복구하세요 — 마지막으로 처리한 시퀀스 번호와 함께 AFTER_SEQUENCE_NUMBER를 사용해 정확히 중단한 지점에서 재개하세요.

무엇을 의미하나요

ExpiredIteratorException: The provided iterator exceeds the maximum age allowed.

DynamoDB 스트림을 직접 읽는 것은 두 단계 루프입니다: GetShardIterator는 샤드로의 위치 핸들을 주고, 각 GetRecords 호출은 이를 소비하고 다음 것(NextShardIterator)을 반환합니다. 그 핸들들 각각은 발급된 지 15분 후에 만료됩니다. 이 예외는 데이터가 사라졌다는 뜻이 아닙니다 — 스트림 레코드는 24시간 동안 유지됩니다 — 단지 이 위치 핸들 이 오래되어 새 것이 필요하다는 뜻입니다.

왜 발생하나요

  • 폴 사이의 느린 처리 — 배치당 수행하는 작업(쓰기, 외부 호출)이 다음 GetRecords 전에 15분보다 오래 걸립니다.
  • 일시 중지되거나 중단된 소비자 — 중지된 워커, 긴 배포, 또는 루프를 붙잡고 있는 디버거 세션.
  • 이터레이터 저장 — 이터레이터 문자열을 (DB나 체크포인트에) 유지하고 나중에 재사용; 이터레이터는 일시적이고 시퀀스 번호는 그렇지 않습니다.
  • 너무 길어진 백오프 — 창을 넘겨 대기한 오류 재시도 루프.

어떻게 고치나요

  1. 이것을 catch하고 마지막 체크포인트에서 이터레이터를 다시 시드하세요 — 마지막으로 처리한 레코드의 SequenceNumber를 추적한 다음:

    const {ShardIterator} = await streams.send(
      new GetShardIteratorCommand({
        StreamArn: streamArn,
        ShardId: shardId,
        ShardIteratorType: 'AFTER_SEQUENCE_NUMBER',
        SequenceNumber: lastProcessedSequenceNumber
      })
    );

    아직 체크포인트가 없나요? TRIM_HORIZON은 가장 오래된 사용 가능한 레코드부터 샤드를 재처리하고, LATEST는 새 활동으로 건너뜁니다.

  2. 이터레이터가 아니라 시퀀스 번호를 체크포인트하세요 — 시퀀스 번호가 내구성 있는 재개 지점입니다.

  3. 폴 루프를 타이트하게 유지하세요 — 무거운 레코드별 작업을 비동기로(큐에 넣어) 처리해 GetRecords 주기가 15분 안에 충분히 머물도록 하세요.

  4. 관리형 소비자를 선호하세요 — Lambda 이벤트 소스 매핑과 DynamoDB Streams Kinesis Adapter(KCL)는 이터레이터와 체크포인트를 대신 관리합니다. 수동으로 만든 GetRecords 루프가 이 예외가 사는 곳입니다.

처리가 멱등한지 확인하세요: 체크포인트에서 재개하면 절반쯤 처리한 레코드가 다시 전달될 수 있습니다. 스트림 자체는 각 레코드를 정확히 한 번 담지만, 마지막 체크포인트에서 다시 시드하는 소비자는 사실상 최소 한 번 처리합니다.

스트림이 실제로 무엇을 방출했는지 디버깅하는 것은 항목이 변하는 것을 볼 수 있을 때 훨씬 쉽습니다 — DynoTable 데스크톱 앱은 항목의 라이브 상태를 보여주므로 스트림 레코드를 데이터와 대조할 수 있습니다. 따라잡기 재생의 읽기 비용을 추정하나요? DynamoDB 요금 계산기가 도와줍니다.

관련 오류

References

공식 AWS 문서(위 링크)를 기준으로 2026-07-13에 마지막으로 검증되었습니다.

Console 없이 DynamoDB 작업하기

DynoTable은 DynamoDB를 위한 빠른 데스크톱 클라이언트입니다 — 테이블을 탐색하고, SQL 스타일 쿼리를 실행하고, 항목을 로컬에서 편집하세요.