Fixes a bug in Kafka auto reset - #12008
Conversation
| // So, it's reasonable to reset the offset the earliest available position | ||
| // | ||
| recordSupplier.seek(streamPartition, earliestAvailableOffset); | ||
| newOffsetInMetadata.put(topicPartition, outOfRangeOffset); |
There was a problem hiding this comment.
Should this be earliestAvailableOffset and not outOfRangeOffset? I will have to trace the sendResetRequestAndWait code to better understand what it expects the offset to be.
There was a problem hiding this comment.
It should be the earliestAvailableOffset. This is a silly mistake. Thanks for pointing it out.
| doReset = true; | ||
| resetPartitions.put(topicPartition, nextOffset); | ||
|
|
||
| if (outOfRangeOffset < earliestAvailableOffset) { |
There was a problem hiding this comment.
I think this logic can further be refined here to call reset within this block itself. Also, it looks like an OffsetOutOfRangeException is thrown when the offset for the partition is either larger or smaller than the range of offsets the server has for the given partition. So the case of earliestAvailableOffset <= outofRangeOffset <= latestAvailableOffset doesn't apply.
So it could look something like this:
if (outOfRangeOffset < earliestAvailableOffset) {
// In this case, it's probably because the messages are no longer in the Kafka cluster i.e. the messages in
// [outOfRangeOffset, earliestAvailableOffset) are lost. Since these lost messages can no longer be
// recovered, it's reasonable to reset the offset to the earliest available position to help ingestion resume.
logger.warn("Seeking kafka offset to earliest offset: " + earliestAvailableOffset);
recordSupplier.seek(streamPartition, earliestAvailableOffset);
// TBD: still need to confirm if this should be outOfRangeOffset or earliestAvailableOffset
newOffsetInMetadata.put(topicPartition, outOfRangeOffset);
logger.warn("Resetting offset in metadata for "
+ topicPartition
+ " to earliest offset: "
+ earliestAvailableOffset);
sendResetRequestAndWait(CollectionUtils.mapKeys(
newOffsetInMetadata,
streamPartition -> StreamPartition.of(
streamPartition.topic(),
streamPartition.partition()
)
), taskToolbox);
} else {
// With the offset not in range (earliestAvailableOffset, latestAvailableOffset), there is not much we can do
// but wait for the available offsets in the partition to arrive in the range.
logger.warn("Offset "
+ outOfRangeOffset
+ " is out of range of the available offsets for "
+ topicPartition
+ ". It is likely that a manual offset reset of the supervisor is needed");
log.warn("Retrying in %dms", task.getPollRetryMs());
pollRetryLock.lockInterruptibly();
try {
long nanos = TimeUnit.MILLISECONDS.toNanos(task.getPollRetryMs());
while (nanos > 0L && !pauseRequested && !stopRequested.get()) {
nanos = isAwaitingRetry.awaitNanos(nanos);
}
}
finally {
pollRetryLock.unlock();
}
}
There was a problem hiding this comment.
@gianm - could you explain the scenario in which the offset we are asking the consumer to seek to could possibly be higher than the latest available offset in Kafka?
@Nonnull
@Override
protected List<OrderedPartitionableRecord<Integer, Long, KafkaRecordEntity>> getRecords(
RecordSupplier<Integer, Long, KafkaRecordEntity> recordSupplier,
TaskToolbox toolbox
) throws Exception
{
try {
return recordSupplier.poll(task.getIOConfig().getPollTimeout());
}
catch (OffsetOutOfRangeException e) {
//
// Handles OffsetOutOfRangeException, which is thrown if the seeked-to
// offset is not present in the topic-partition. This can happen if we're asking a task to read from data
// that has not been written yet (which is totally legitimate). So let's wait for it to show up
//
log.warn("OffsetOutOfRangeException with message [%s]", e.getMessage());
possiblyResetOffsetsOrWait(e.offsetOutOfRangePartitions(), recordSupplier, toolbox);
return Collections.emptyList();
}
}
There was a problem hiding this comment.
For a partition that we've already committed some offset for, the starting offset given to a task for that partition is going to be the committed offset plus 1. So if no new messages have been written since the last commit, the starting offset will not exist yet.
There was a problem hiding this comment.
Thanks for the clarification, @gianm!
@FrankChen021 - I would probably get rid of the log line I mentioned then and have the else block as it is (but moved as else condition for if (outOfRangeOffset < earliestAvailableOffset)
There was a problem hiding this comment.
@samarthjain I kept the code block as it was because original code reset the meta for all partition out of the partition loop and only reset for one time.
|
@samarthjain I'm almost exhausted these days. Give me more days to resolve your comments. Thanks! |
Signed-off-by: frank chen <frank.chen021@outlook.com>
|
Hello, can we have a status on this merge ? Is it plan to merge it shortly ? Thanks |
|
This pull request has been marked as stale due to 60 days of inactivity. |
|
This pull request/issue has been closed due to lack of activity. If you think that |
Fixes #11658
Description
The bug is detailed described in the issue above.
This PR fixes
useEarliestOffsetoruseLatestOffsetconfiguration parameters.This PR has: