[13.x] Start a new max wait window after a debounced job runs - #61281
Merged
taylorotwell merged 2 commits intoAug 23, 2026
Merged
Conversation
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.
tl;dr a debounced job that already ran can still make the next dispatch skip its debounce completely.
maxWaiton#[DebounceFor]keeps a:first_dispatched_atcache key, written on the first dispatch of a burst. it gets cleared in exactly two spots: whenmaxWaitactually trips, and fromDebounceLock::release()on a transaction rollback. nothing clears it when the job just runs normally.so it outlives the burst it belonged to. ttl is
max($debounceFor * 10, 300), ie at least 5 minutes, and any dispatch inside that window is measuring elapsed time against a burst thats already finished. if the gap is bigger thanmaxWaitthe job gets treated as overdue and queued withdelay = 0:so the first event of any burst that starts more than
maxWaitafter the last one doesnt get debounced at all. queued listeners with#[DebounceFor]do the same thing, both paths go throughCallQueuedHandler.fix just clears the max wait timestamp once a job is confirmed not superseded and is about to run. next dispatch then opens a fresh window.
i did think about reusing
DebounceLock::release()there instead, but that also forgets the owner token andtestTokenPersistsAfterSuccessfulExecutionkeeps that on purpose. drop it and a superseded job still sitting on the queue would see an empty cache and run via the fail-open branch. hence the narrowerreleaseMaxWait().one test change worth flagging:
testMaxDebounceWaitForcesImmediateExecutionnow skipssync. it needs three dispatches to pile up while the jobs stay queued, but onsyncevery dispatch runs immediately, so by the second one (t=50, debounce 30) the first job has already run. it was only green because of the stale timestamp. five of the other tests in that file already skipsyncanyway, and it still runs underdatabaseandredis.