[ 
https://issues.apache.org/jira/browse/CAMEL-24154?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen reassigned CAMEL-24154:
-----------------------------------

    Assignee: Claus Ibsen

> camel-aws2-ddb - DDB Streams consumer never subscribes to shards created 
> after startup - silent data loss on resharding
> -----------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24154
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24154
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-aws
>            Reporter: Federico Mariani
>            Assignee: Claus Ibsen
>            Priority: Critical
>              Labels: review-2026-07
>         Attachments: ShardIteratorHandlerReshardingTest.java
>
>
> Found during a code review of camel-aws2-ddb on main (4.22.0-SNAPSHOT).
> In {{ShardIteratorHandler.getShardIterators()}} (ddbstream, lines ~49-77), 
> {{shardTree.populate(...)}} is only called when 
> {{currentShardIterators.isEmpty()}} — i.e. on the first poll, or after *all* 
> tracked shards have been drained and removed. On every later poll the 
> else-branch resolves successors of a closed shard against that stale 
> snapshot: {{shardTree.getChildren(shardId)}}. Children created by DynamoDB's 
> routine shard rotation (roughly every 4 hours) or by a split *after* the 
> initial {{describeStream}} are not in the tree, so {{children.isEmpty()}} is 
> true and the closed shard is treated as "still an active leaf". Once its 
> records are drained, {{updateShardIterator(shardId, null)}} removes it and 
> its lineage is never followed.
> While at least one other shard remains active the iterator map never empties, 
> so the tree is never refreshed:
> * On a table with 2+ partitions, after any partition's shard rotates, *all 
> subsequent writes to that partition are silently never delivered* — for 
> hours, until every other shard also happens to close.
> * On a single-partition table the map does empty, but re-initialization uses 
> the *configured* iterator type: with the default {{FROM_LATEST}} the records 
> written between the parent closing and re-initialization are skipped; with 
> {{FROM_START}} the entire 24h trim-horizon backlog is re-delivered as 
> duplicates every ~4h.
> Related defects in the same class (kept here for context, listed in the 
> umbrella): {{getShardIterators()}} returns the internal HashMap by reference 
> while {{updateShardIterator}} structurally modifies it during the consumer's 
> iteration (ConcurrentModificationException when a shard retires); 
> {{describeStream}} pagination ({{lastEvaluatedShardId}}) is ignored so 
> streams with >100 shards lose partitions; and {{requestFreshShardIterator}} 
> sends {{AFTER_SEQUENCE_NUMBER}} with a null sequence number when the iterator 
> expired before any record was seen, leaving the consumer permanently stuck.
> *Reproducer*: attached {{ShardIteratorHandlerReshardingTest.java}} (unit test 
> with a mutable mock streams client, goes under 
> {{components/camel-aws/camel-aws2-ddb/src/test/java/org/apache/camel/component/aws2/ddbstream/}}).
>  Two active shards A and B; A rotates into children A1/A2; after A is drained 
> the handler keeps polling only B:
> {noformat}
> children of the rotated shard-A must be consumed, but the handler returned 
> only: {shard-B=iterator-B}
> {noformat}
> *Suggested fix*: when a tracked shard closes (children lookup empty or 
> {{nextShardIterator == null}}), re-issue a paginated {{describeStream}} to 
> refresh the tree and start the closed shard's children at {{TRIM_HORIZON}}.
> _This issue was researched and filed by Claude Code (AI) on behalf of 
> Federico Mariani (fmariani). Full findings document from the review is 
> attached to the umbrella issues._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to