Skip to content

Resolve debounce race condition - #2356

Merged
matthiask merged 5 commits into
django-commons:mainfrom
codingjoe:debounce
Apr 22, 2026
Merged

Resolve debounce race condition#2356
matthiask merged 5 commits into
django-commons:mainfrom
codingjoe:debounce

Conversation

@codingjoe

@codingjoe codingjoe commented Apr 21, 2026

Copy link
Copy Markdown
Member

Description

Debounce didn't cancel the execution but only delayed the resolution. It then resolved multiple times with the same values, causing the resulting code to be called multiple times in direct succession on multiple threads.

This can not only result in multiple DOM updates but also in race conditions.

Note

This uses Promise.try, Baseline 2025 "newly available". Since we are in a debug and developer context, I much prefer the beautify simplify it provides, even if Opera Mini doesn't support it.
That no one found this bug in years underlines my point ;)

Checklist:

  • I have added the relevant tests for this change.
  • I have added an item to the Pending section of docs/changes.rst.

AI/LLM Usage

  • [ ] This PR includes code generated with the help of an AI/LLM

Comment thread tests/js/utils.test.js
const slowjax = debounce(ajax, 200);

function handleAjaxResponse(requestId) {
const handleAjaxResponse = debounce(async (requestId) => {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of throttling the request, we debounce the entire function and properly cancel it if it is replaced by a new call.

@github-actions

Copy link
Copy Markdown

Coverage report

This PR does not seem to contain any modification to coverable code.

debounce didn't cancel the execution but only deplayed the resolution.
It then resolved multiple times with the same values casing the resulting
code to be called multiple times in direct succession on multiple threads.

This can not only resolve into multipe DOM updates but also to race conditions.
@codingjoe
codingjoe requested review from Copilot and matthiask April 21, 2026 12:40
@codingjoe codingjoe self-assigned this Apr 21, 2026
@codingjoe
codingjoe marked this pull request as ready for review April 21, 2026 12:41
@codingjoe
codingjoe removed the request for review from matthiask April 21, 2026 12:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a race condition caused by the existing debounce implementation resolving multiple pending calls, which could trigger repeated UI updates for rapid history-panel fetches.

Changes:

  • Reworked debounce to cancel prior scheduled invocations instead of resolving multiple pending calls.
  • Updated toolbar AJAX update flow to debounce the handler rather than debouncing ajax() calls with multiple .then(...) continuations.
  • Adjusted JS unit tests and added a changelog entry.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
debug_toolbar/static/debug_toolbar/js/utils.js Reimplements and documents debounce, updates module exports.
debug_toolbar/static/debug_toolbar/js/toolbar.js Refactors AJAX update logic to use the revised debounce behavior and avoid repeated DOM updates.
tests/js/utils.test.js Updates debounce tests for the new behavior (sync + async cases).
docs/changes.rst Adds a Pending changelog entry for the debounce race condition fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread debug_toolbar/static/debug_toolbar/js/utils.js
Comment thread debug_toolbar/static/debug_toolbar/js/utils.js
Comment thread debug_toolbar/static/debug_toolbar/js/toolbar.js Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@codingjoe
codingjoe requested a review from matthiask April 21, 2026 12:50
@codingjoe

Copy link
Copy Markdown
Member Author

I don't know why the linter hates me. I didn't even touch the Python code :/

@matthiask matthiask left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promise.try is very new; it is only available in Firefox since the beginning of 2025. I think that's fine since people can test their sites in Browserstack or whatever without the toolbar enabled if they encounter errors, but it's something to keep in mind.

@django-commons/django-debug-toolbar-committers Does anyone have any reservations regarding browser compatibility?

Comment thread tests/js/utils.test.js
@matthiask

Copy link
Copy Markdown
Member

I don't know why the linter hates me. I didn't even touch the Python code :/

changes.rst:7: : Spell check: debounce: Prevent debounce race conditions in the history panel for rapid.

Maybe debounce has to be added to docs/spelling_wordlist.txt?

@codingjoe

Copy link
Copy Markdown
Member Author

Ok, done. Ready form my side. Unless there are any concerns. I amended the changes in new comments; feel free to squash merge, but I can also rebase 🤷‍♂️

@elineda

elineda commented Apr 22, 2026

Copy link
Copy Markdown
Member

Promise.try is very new; it is only available in Firefox since the beginning of 2025. I think that's fine since people can test their sites in Browserstack or whatever without the toolbar enabled if they encounter errors, but it's something to keep in mind.

@django-commons/django-debug-toolbar-committers Does anyone have any reservations regarding browser compatibility?

Firefox esr is at version 140 so It should be find with organisation.

That's seem a good time to add a section prequesite with minimal browser configuration. Promise should be the newer fonction with us so take the minimal for it.

@matthiask
matthiask merged commit fc93765 into django-commons:main Apr 22, 2026
29 checks passed
@matthiask

Copy link
Copy Markdown
Member

Thanks @elineda for the review! I'm working on an addition to the docs now.

Thanks @codingjoe!

I almost always use squash merges here except on larger changes where preserving the steps makes the history more understandable later. Cleaning up the history manually isn't worth anyones time elsewise.

matthiask added a commit that referenced this pull request Apr 22, 2026
… modern browser (#2357)

Co-authored-by: Johannes Maron <johannes@maron.family>
@codingjoe
codingjoe deleted the debounce branch April 23, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants