fix(kinesis): Fix shard end coordination race condition - #3453
Conversation
ShardProcessor now tracks the last record of each batch with a semaphore to prevent premature shard checkpoint when KCL delivers an empty final batch. Previously, when the final batch was empty, shardEnded would complete immediately and checkpoint the shard before in-flight records from the previous batch were checkpointed, causing those checkpoint attempts to fail. Changes: - Replace single Semaphore with Option[Semaphore] that tracks the last record of each non-empty batch - shardEnded now waits on the most recent semaphore before checkpointing - Add ShardProcessorSpec with tests covering normal flow, empty final batch scenario, and no records case Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Hi @huajiang-tubi, Thank you for your contribution! We really value the time you've taken to put this together. Before we proceed with reviewing this pull request, please sign the Akka Contributors License Agreement: |
|
I have signed sign the CLA. |
|
@huajiang-tubi I have closed and re-opened this PR and now the CLA validator looks ok. |
Can you share more details around this? I am not able to open this change. |
We observed checkpoint failures during scaling up of a kinesis stream. It was caused by checkpoint with sequence number after SHARD_END had been checkpointed. The current implementation of |
…tplus-mockito dependency Replace org.scalatestplus.mockito.MockitoSugar.mock (not in project deps) with a local helper using org.mockito.Mockito.mock directly. Also remove IntegrationPatience mixin which requires AbstractPatienceConfiguration self-type not provided by DefaultTestContext. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
johanandren
left a comment
There was a problem hiding this comment.
LGTM
I pushed a tiny improvement to the test on top of the changes.
Summary
ShardProcessorwhere premature shard checkpoint occurs when KCL delivers an empty final batchShardProcessorSpecwith comprehensive test coverage for the coordination scenariosProblem
The original implementation used a single
Semaphore(1)that was acquired whenisAtShardEndwas true. This created a race condition:isAtShardEnd=false, the records are processed normallyisAtShardEnd=true(this is valid KCL behavior)shardEndedmethod is called, but since no records were in the final batch, no semaphore coordination happenedshardEndedimmediately checkpoints the shard withSHARD_ENDSolution
Replace the single semaphore approach with a per-batch tracking mechanism:
Semaphore(0)for the last record of each batch (empty batches create no semaphore)Option[Semaphore](volatile) so it persists across batchesshardEndedis called, wait on the most recent semaphore (which correctly points to the previous batch's last record if the final batch is empty)Test Coverage
Added
ShardProcessorSpecwith three test scenarios:shardEndeduntil the last record is checkpointedshardEndeduntil the previous batch's last record is checkpointed (the critical bug fix)shardEndedimmediately when no records were ever processedRelated
This bug was discovered and fixed in https://github.com/adRise/hyades/pull/3668 and has been ported to alpakka.
🤖 Generated with Claude Code