debezium/dbz#2523 Fix possible infinite retry loop on bounded change stream partitions - #175
Merged
Naros merged 2 commits intoSep 1, 2026
Conversation
…rtitions When a bounded change stream partition query (endTimestamp != null) completes (resultSet.next() == false), the backend query has scanned all rows up to endTimestamp. In Cloud Spanner's Change Stream TVF (AwaitChangeIterator), an OuterApply is performed against the change data table for each time slice: 1. If no mutations exist in the slice, Spanner emits a HeartbeatRecord with timestamp = endTimestamp. 2. If a mutation exists in the slice, Spanner emits DataChangeRecord and does not emit a trailing HeartbeatRecord at endTimestamp. Requiring lastReceivedTimestamp >= endTimestamp caused bounded queries ending with a DataChangeRecord at T < endTimestamp to throw ChangeStreamException and retry from T indefinitely because start_timestamp is inclusive. This fix: 1. Updates reachedEnd in SpannerChangeStreamService to allow bounded queries (partition.getEndTimestamp() != null) to complete normally on EOF without requiring lastReceivedTimestamp >= endTimestamp. 2. Preserves the validation that unbounded queries (endTimestamp == null) must receive ChildPartitionsEvent before completing, continuing to protect against silent stream dropouts. 3. Updates unit tests in SpannerChangeStreamServiceTest. Signed-off-by: Nancy Xu <nancyxu@google.com>
jiangzzhu
approved these changes
Sep 1, 2026
Naros
reviewed
Sep 1, 2026
Naros
left a comment
Member
There was a problem hiding this comment.
Hi @nancyxu825 this LGTM, do you want to cleanup the one local variable below or are you okay leaving it as-is?
…eStreamService Remove unused lastReceivedTimestamp variable and timestamp tracking logic following the simplification of stream completion checks. Signed-off-by: Nancy Xu <nancyxu@google.com>
Member
|
Applied, thanks @nancyxu825 and @jiangzzhu 🎉 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a bounded change stream partition query (endTimestamp != null) completes (resultSet.next() == false), the backend query has scanned all rows up to endTimestamp.
Requiring lastReceivedTimestamp >= endTimestamp caused bounded queries ending with a DataChangeRecord at T < endTimestamp to throw ChangeStreamException and retry from T indefinitely because start_timestamp is inclusive.
This fix: