Skip to content

Commit

Permalink
Async compatible HistoryPanel (#1991)
Browse files Browse the repository at this point in the history
* async compatible history panel

* Update debug_toolbar/toolbar.py
  • Loading branch information
salty-ivy committed Aug 27, 2024
1 parent 423ad36 commit c401513
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
1 change: 1 addition & 0 deletions debug_toolbar/panels/history/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
class HistoryPanel(Panel):
"""A panel to display History"""

is_async = True
title = _("History")
nav_title = _("History")
template = "debug_toolbar/panels/history.html"
Expand Down
19 changes: 13 additions & 6 deletions debug_toolbar/toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.asgi import ASGIRequest
from django.dispatch import Signal
from django.template import TemplateSyntaxError
from django.template.loader import render_to_string
Expand Down Expand Up @@ -101,12 +102,18 @@ def should_render_panels(self):
If False, the panels will be loaded via Ajax.
"""
if (render_panels := self.config["RENDER_PANELS"]) is None:
# If wsgi.multiprocess isn't in the headers, then it's likely
# being served by ASGI. This type of set up is most likely
# incompatible with the toolbar until
# https://github.com/jazzband/django-debug-toolbar/issues/1430
# is resolved.
render_panels = self.request.META.get("wsgi.multiprocess", True)
# If wsgi.multiprocess is true then it is either being served
# from ASGI or multithreaded third-party WSGI server eg gunicorn.
# we need to make special check for ASGI for supporting
# async context based requests.
if isinstance(self.request, ASGIRequest):
render_panels = False
else:
# The wsgi.multiprocess case of being True isn't supported until the
# toolbar has resolved the following issue:
# This type of set up is most likely
# https://github.com/jazzband/django-debug-toolbar/issues/1430
render_panels = self.request.META.get("wsgi.multiprocess", True)
return render_panels

# Handle storing toolbars in memory and fetching them later on
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Problematic Parts
- Support for async and multi-threading: ``debug_toolbar.middleware.DebugToolbarMiddleware``
is now async compatible and can process async requests. However certain
panels such as ``SQLPanel``, ``TimerPanel``,
``RequestPanel``, ``HistoryPanel`` and ``ProfilingPanel`` aren't fully
``RequestPanel`` and ``ProfilingPanel`` aren't fully
compatible and currently being worked on. For now, these panels
are disabled by default when running in async environment.
follow the progress of this issue in `Async compatible toolbar project <https://github.com/orgs/jazzband/projects/9>`_.
18 changes: 17 additions & 1 deletion tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from django.db import connection
from django.http import HttpResponse
from django.template.loader import get_template
from django.test import RequestFactory
from django.test import AsyncRequestFactory, RequestFactory
from django.test.utils import override_settings

from debug_toolbar.forms import SignedDataForm
Expand Down Expand Up @@ -126,6 +126,22 @@ def test_should_render_panels_multiprocess(self):
request.META.pop("wsgi.multiprocess")
self.assertTrue(toolbar.should_render_panels())

def test_should_render_panels_asgi(self):
"""
The toolbar not should render the panels on each request when wsgi.multiprocess
is True or missing in case of async context rather than multithreaded
wsgi.
"""
async_request = AsyncRequestFactory().get("/")
# by default ASGIRequest will have wsgi.multiprocess set to True
# but we are still assigning this to true cause this could change
# and we specifically need to check that method returns false even with
# wsgi.multiprocess set to true
async_request.META["wsgi.multiprocess"] = True
toolbar = DebugToolbar(async_request, self.get_response)
toolbar.config["RENDER_PANELS"] = None
self.assertFalse(toolbar.should_render_panels())

def _resolve_stats(self, path):
# takes stats from Request panel
request = rf.get(path)
Expand Down

0 comments on commit c401513

Please sign in to comment.