Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache panel work #1626

Merged
merged 5 commits into from
May 23, 2022
Merged

Cache panel work #1626

merged 5 commits into from
May 23, 2022

Conversation

living180
Copy link
Contributor

This PR re-architects CachePanel call recording. Using signals for monitoring cache calls gives incorrect results in the face of concurrency. If two requests are being processed concurrently in different threads, they will store each other's cache calls because both panels will be subscribed to the same signal. This PR updates the code to record the cache calls directly via a method on the panel instance rather than going through signals.

Additionally, it reworks the enable_instrumentation() mechanism to monkey patch methods on the cache instances directly instead of replacing the cache instances with wrapper classes. This should eliminate the corner cases mentioned in the (now-removed) disable_instrumentation() comments.

One change I made as part of the preparatory work for these changes is adding a ready() class method to the panel API, to be called from the DebugToolbarConfig.ready() method. This provides a clean way for panels to perform any initialization or instrumentation that needs to be done unconditionally for the panel regardless of whether it is enabled for a particular request. This in theory could cause backwards compatibility issues if a third-party panel already had a ready method or attribute. I did check all the third-party panels listed in the Debug Toolbar documentation, and none of them would be affected by this change. However, if there are still backwards compatibility concerns about the addition of this method, I can rework this part of the PR.

@living180
Copy link
Contributor Author

FYI, I think this should also fix #799 (though that was not my goal when I started working on these changes).

@living180 living180 force-pushed the cache_panel_work branch 2 times, most recently from 7eee842 to 9eff0ac Compare May 23, 2022 14:06
Copy link
Member

@matthiask matthiask left a comment

Choose a reason for hiding this comment

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

I like it, thanks!

debug_toolbar/apps.py Outdated Show resolved Hide resolved
setup.cfg Outdated Show resolved Hide resolved
from django.dispatch import Signal

# Signal used internally for testing
toolbar_created = Signal()
Copy link
Member

Choose a reason for hiding this comment

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

I know it's not documented but I'm a little bit uneasy; this signal instance sounds or looks a bit too public to me.

Maybe make this _toolbar_created, and/or maybe even move this to the debug_toolbar/toolbar.py module to lower its visibility?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made it a class attribute on the DebugToolbar class under the name _created. Hopefully that will lower its profile?

living180 added 3 commits May 23, 2022 19:49
Will be used for asgiref.local.Local, a context-aware threadlocal.local
replacement also used internally by Django.  Depend on the same version
required by the earliest supported version of Django (3.2).
Add a mechanism for integration tests to access the toolbar used for a
particular request:  Update DebugToolbar to emit a signal on creation
referencing itself.  Then create and use a custom Django test client
that connects to this signal to capture the toolbar that was created
while the request was being processed, and to store the toolbar on the
response for use by tests.
For integration tests using the cache panel, check the panel associated
with the toolbar created for the request, rather than the toolbar
created for the test case.
living180 added 2 commits May 23, 2022 20:02
This method will be called for all installed panels from the
DebugToolbarConfig.ready() method during Django initialization to
support initialization that needs to happen unconditionally for the
panel regardless of whether it is enabled for a particular request.
Using signals for monitoring cache calls gives incorrect results in the
face of concurrency.  If two requests are being processed concurrently
in different threads, they will store each other's cache calls because
both panels will be subscribed to the same signal.

Additionally, rework the enable_instrumentation() mechanism to
monkey patch methods on the cache instances directly instead of
replacing the cache instances with wrapper classes.  This should
eliminate the corner cases mentioned in the (now-removed)
disable_instrumentation() comments.
@living180 living180 requested a review from matthiask May 23, 2022 18:06
matthiask added a commit that referenced this pull request May 23, 2022
Depending on asgiref via Django is fine. Refs #1626.
@matthiask matthiask merged commit ce553bf into django-commons:main May 23, 2022
@matthiask
Copy link
Member

Thank you!

@living180 living180 deleted the cache_panel_work branch May 23, 2022 18:12
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.

2 participants