Fix: Handle empty retained partitions - #2589
Open
ngyngcphu wants to merge 1 commit into
Open
Conversation
When a partition has no retained records, there is no readable offset to consume from. Console still tried to read from the last possible offset, which produced an offset outside the retained range. Treat partitions without retained records as empty.
There was a problem hiding this comment.
Pull request overview
This PR addresses a Kafka edge case where a partition can become “logically empty” after retention deletes all records (earliest == latest), which previously could lead Console to compute an invalid start offset and trigger offset-out-of-range / stalled consumption behavior.
Changes:
- Treat partitions with
latest <= earliestas empty when calculating timestamp-based start offsets. - Clamp timestamp-resolved offsets to the retained range.
- Add a regression test for timestamp lookup returning
-1with equal low/high watermarks.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| backend/pkg/console/list_messages.go | Adjusts consume-request start offset selection for timestamp mode when watermarks indicate an empty retained partition. |
| backend/pkg/console/list_messages_test.go | Adds a regression test using a fake cluster to reproduce timestamp lookup returning -1 on an empty retained partition. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+430
to
+434
| if endOffset.Offset <= startOffset.Offset { | ||
| p.StartOffset = startOffset.Offset | ||
| break | ||
| } | ||
| if offset < 0 || offset >= endOffset.Offset { |
Comment on lines
+105
to
+117
| req := &ListMessageRequest{ | ||
| TopicName: topicName, | ||
| PartitionID: partitionsAll, | ||
| StartOffset: StartOffsetTimestamp, | ||
| StartTimestamp: timestamp, | ||
| MessageCount: 10, | ||
| } | ||
|
|
||
| // Pass the same offsets as earliest and latest to model an empty partition. | ||
| actual, err := (&Service{}).calculateConsumeRequests(t.Context(), client, req, []int32{0}, offsets, offsets) | ||
| require.NoError(t, err) | ||
| assert.Empty(t, actual) | ||
| } |
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.
Issue
When reading topic messages, Console can calculate an invalid start offset if retention has already deleted all records from a partition. One example is a topic with:
After the retention window passes, Kafka can delete all messages from the topic. At that point the partition has no readable records.

Error from backend:
In that state Kafka reports the same earliest and latest offsets, for example:
This PR treats partitions with
latest <= earliestas empty before choosing a read offset, so Console does not request an offset outside the retained range.Before fix, run test
TestCalculateConsumeRequests_TimestampEmptyRetainedPartition, got error:After fix, run test
TestCalculateConsumeRequests_TimestampEmptyRetainedPartitionsuccessfully: