[fix][broker] Prevent early replay of non-strict delayed messages#26188
Merged
Conversation
Assisted-by: Codex (GPT-5)
lhotari
approved these changes
Jul 14, 2026
Member
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.
Motivation
InMemoryDelayedDeliveryTrackerrounds non-strict delivery timestamps down to reduce the number of timestamp keys. Availability checks currently compare that bucket start directly with the non-strict cutoff (now + tickTimeMillis).The original
deliverAtcan be up toprecisionMillis - 1later than the bucket start. As a result, the tracker can expose a position before the original timestamp is inside the configured early-delivery window. The dispatcher then reads the entry,addMessagechecks the originaldeliverAt, and inserts the same position back into an already eligible bucket. An active dispatcher can repeat this replay until the original timestamp reaches the cutoff, causing unnecessary reads.With the default 1000 ms tick and 512 ms timestamp buckets, this inconsistent window can be up to 511 ms.
Regression source and related changes
Modifications
Verifying this change
This change added tests and can be verified as follows:
./gradlew :pulsar-broker:test --tests 'org.apache.pulsar.broker.delayed.InMemoryDeliveryTrackerTest' -PtestRetryCount=0./gradlew quickCheckThe new regression test was also verified against the unpatched implementation: the same position was replayed and re-added 10 times while the clock remained fixed. With the fix it is replayed zero times before the early-delivery window, then exactly once after the full bucket enters that window.
Does this pull request potentially affect one of the following parts: