Skip to content

Fixes #2073 -- Added DatabaseStore for persistent debug data storage. #2121

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

Open
wants to merge 10 commits into
base: serializable
Choose a base branch
from

Conversation

dr-rompecabezas
Copy link
Member

Description

  • Introduced DatabaseStore to store debug toolbar data in the database.
  • Added DebugToolbarEntry model and migrations for persistent storage.
  • Updated documentation to include configuration for DatabaseStore.
  • Added tests for DatabaseStore functionality, including CRUD operations and cache size enforcement.

Fixes #2073

Checklist:

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

- Introduced `DatabaseStore` to store debug toolbar data in the database.
- Added `DebugToolbarEntry` model and migrations for persistent storage.
- Updated documentation to include configuration for `DatabaseStore`.
- Added tests for `DatabaseStore` functionality, including CRUD
  operations and cache size enforcement.

Fixes django-commons#2073
@matthiask
Copy link
Member

matthiask commented Apr 3, 2025

Tests are all failing, you'd probably have to do a merge of main to get all the CSP fixes, but that's hard. So let's concentrate on the branch.

@dr-rompecabezas
Copy link
Member Author

The only failing tests are unrelated to this PR. Both tests have already been fixed, but the fixes have not yet been merged into the serializable branch.

   ======================================================================
  ERROR: test_exists (tests.test_csp_rendering.CspRenderingTestCase)
  A `nonce` should exist when using the `CSPMiddleware`.
  ----------------------------------------------------------------------
   ======================================================================
  ERROR: test_redirects_exists (tests.test_csp_rendering.CspRenderingTestCase)
  ----------------------------------------------------------------------

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 this a lot. Sorry for the nitpicky review comments.

def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
"""Save the panel data for the given request_id"""
# First ensure older entries are cleared if we exceed cache size
cls.set(request_id)
Copy link
Member

Choose a reason for hiding this comment

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

I wonder what the set method is for. @tim-schilling , do you remember what the thinking behind it was when we have save_panel to really do saving?

The call can probably be removed here because we're immediately doing get_or_create afterwards, so if the entry doesn't exist already saving the panel data works anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll push the rest of changes for now, while this is being discussed.

For reference, here's our the save_panel method was implemented in MemoryStore, including the set method call.

    @classmethod
    def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
        """Save the panel data for the given request_id"""
        cls.set(request_id)
        cls._request_store[request_id][panel_id] = serialize(data)

We can also call _cleanup_old_entries directly rather than set to call _cleanup_old_entries, if I understand the purpose correctly.

Copy link
Member

Choose a reason for hiding this comment

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

cls.set() is meant to create the record for the request in the toolbar's store. For the MemoryStore, there's a separate collection of ids from the actual store. I suspect it's for performance more than anything.

- Updated model name from `DebugToolbarEntry` to `HistoryEntry` to make
  string representations of the app_model less redundant.
- Adjusted verbose names to use translations with `gettext_lazy`.
- Updated all references in `store.py` to use the new model name.
- Modified tests to reflect the model name change.
- Added a test to check the default ordering of the model and make it
  the defaul ordering in methods reliable.
Fix verbose names and capitalization.
Fix verbose name
@matthiask
Copy link
Member

By the way, you could try pinning django-csp<4 in this branch again, this would probably allow the tests to pass. And you don't have to worry about merging main for now.

@dr-rompecabezas
Copy link
Member Author

Good. I'll try pinning CSP. That way, I can also rest assured that's the only cause of the failing tests.

@dr-rompecabezas
Copy link
Member Author

I'll look into the failing (MySQL) tests later today. Good that we pinned django-csp. Otherwise, I would have assumed that was the only reason for the failing tests.

@dr-rompecabezas dr-rompecabezas marked this pull request as draft April 4, 2025 04:58
@matthiask
Copy link
Member

matthiask commented Apr 4, 2025

The MariaDB failure has to do with using LIMIT and subqueries. It seems my suggestion to use .exclude(...[:25]).delete() broke the MariaDB test. There may be a reason for using list() after all.

@dr-rompecabezas dr-rompecabezas marked this pull request as ready for review April 4, 2025 16:01
HistoryEntry.objects.filter(request_id=request_id).delete()

@classmethod
def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
Copy link
Member

Choose a reason for hiding this comment

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

Similar to set(), do we want to use transaction.atomic() here as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

This comment is showing under panel()... I wonder if somehow the comment shifted and it was meant for save_panel().

Copy link
Member

Choose a reason for hiding this comment

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

I meant this comment for both methods.

Copy link
Member

Choose a reason for hiding this comment

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

As per our call, there's a concern about panels updating this concurrently and needing to avoid clearing another panel's data when saving.

@dr-rompecabezas
Copy link
Member Author

I applied some of the changes suggested by @tim-schilling without attempting to simplify tests yet to see if all tests pass in CI.

@matthiask
Copy link
Member

@tim-schilling I'm good with this, and I hope we can get serialized merged soon? Maybe I should do a quick release containing everything else first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants