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

Fixed #34806 -- Made the cached_db backend resilient to cache backend errors. #17220

Merged
merged 1 commit into from Feb 22, 2024

Conversation

sulabhkatila
Copy link
Contributor

ticket_34806

I have added a MemoryError handling to ensure that it doesn't crash and logged the issue to let the user know.

Copy link
Contributor

@shangxiao shangxiao left a comment

Choose a reason for hiding this comment

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

Hi & thanks for submitting this PR 😊

There's a change required to the way the logger is created. Also we'll need a new test to confirm the behaviour change.

Comment on lines 58 to 60
import logging

logging.error(f"Caching error: {e}")
Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately we can't just log willy-nilly, we have to follow the standard process of getting a named logger and logging to that to allow users of the framework to capture those logs.

I'm not sure myself what the appropriate logger is for this module but nessita or felixx will be able to confirm that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the feedback and guidance.

Once I have the information from @felixxm or @nessita, I'll make the necessary updates to the code accordingly.

Copy link
Contributor

Choose a reason for hiding this comment

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

I did talk with Mariusz about this, and he confirmed that:

  • we should use a new logger for django.contrib.sessions:
import logging

logging.getLogger("django.contrib.sessions")
  • we should add a release note about the adding of this logger and a documentation entry in ref/logging

Copy link
Contributor

Choose a reason for hiding this comment

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

@sulabhkatila Any chance you missed the comment above? I don't see those changes reflected in the current diff.

try:
super().save(must_create)
self._cache.set(self.cache_key, self._session, self.get_expiry_age())
except MemoryError as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

@claudep Is this the correct exception to catch?

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure we can target any specific exception type. In my use case, it was a TooBig error generated by pylibmc. It looks like the error is defined in https://github.com/lericson/pylibmc/blob/97ace274cffd8db/src/_pylibmcmodule.h#L201C12-L201C12 and raised from C code. I'm afraid we have no real choice than catching the broader Exception base class.

@shangxiao
Copy link
Contributor

There's a change required to the way the logger is created. Also we'll need a new test to confirm the behaviour change.

Oh and there may be some documentation updates as well to let folks know "from x.xx version caching errors will result in logs"… felix & nessita will confirm this though 👍

@nessita nessita changed the title Ticket 34806 Fixed #34806 -- Made the cached_db backend resilient to cache backend errors. Sep 14, 2023
@nessita
Copy link
Contributor

nessita commented Sep 14, 2023

I don't have the answers to the logger questions but I'll check with @felixxm in our next catch up, and get back to you (in about a week).

In the meantime, any chance that the lint errors are fixed?

@sulabhkatila
Copy link
Contributor Author

hi @nessita, can you please lead me in the right direction in terms of adding a test case for this?

@shangxiao
Copy link
Contributor

@sulabhkatila Nessita's busy, I can help. You've already added a test? 🤔

@shangxiao
Copy link
Contributor

@sulabhkatila A good starting logger may be django.request. Have a look at the codebase for existing uses, eg logger = getLogger("django.request"). Usually loggers at created at module-level and placed at the top after the imports.

@sulabhkatila
Copy link
Contributor Author

sulabhkatila commented Sep 19, 2023

@sulabhkatila Nessita's busy, I can help. You've already added a test? 🤔

Hi @shangxiao,
I added the test but it actually doesn't really work. I only added that to show where my head was going with the test. So my idea for the test was to try to recreate the error and get the test case to catch any error that would be raised (Thought it would be the way from here).

But it doesn't really work: the test case passes even when we raise the error here instead of passing (how it is done now).

I am now suspicious if I am even catching the exception properly as if there isn't where the exception is raised??

Copy link
Contributor

@shangxiao shangxiao left a comment

Choose a reason for hiding this comment

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

Getting better 🎉

import logging

logger = logging.getLogger("django.request")
logger.error("Error saving to cache: %s", e)
Copy link
Contributor

Choose a reason for hiding this comment

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

Optionally we can do logger.exception(<message>) which captures the exception:

https://docs.python.org/3/library/logging.html#logging.Logger.exception

This hasn't been used in Django yet so let's wait to see what Mariusz thinks.

tests/sessions_tests/tests.py Outdated Show resolved Hide resolved
django/contrib/sessions/backends/cached_db.py Outdated Show resolved Hide resolved
@sulabhkatila
Copy link
Contributor Author

Hi @shangxiao, i have made the proposed changes and also tried to update the documentation in this commit.

docs/topics/cache.txt Outdated Show resolved Hide resolved
@shangxiao
Copy link
Contributor

Hi @shangxiao, i have made the proposed changes and also tried to update the documentation in this commit.

Thanks 🏆 The logger still isn't at module-level but nessita may be ok with that.

@nessita
Copy link
Contributor

nessita commented Oct 31, 2023

Hi @shangxiao, i have made the proposed changes and also tried to update the documentation in this commit.

Thanks 🏆 The logger still isn't at module-level but nessita may be ok with that.

Thanks for the ping, looking into this now!

@nessita
Copy link
Contributor

nessita commented Oct 31, 2023

There's a change required to the way the logger is created. Also we'll need a new test to confirm the behaviour change.

Oh and there may be some documentation updates as well to let folks know "from x.xx version caching errors will result in logs"… felix & nessita will confirm this though 👍

Yes, I think we do need a release note stating this and the adding of the new logger.

@nessita
Copy link
Contributor

nessita commented Oct 31, 2023

Hi @shangxiao, i have made the proposed changes and also tried to update the documentation in this commit.

Thanks 🏆 The logger still isn't at module-level but nessita may be ok with that.

I am not OK with that :-)

Please let's move the getLogger code to right after the imports, at the module level. Thanks!

Copy link
Contributor

@nessita nessita left a comment

Choose a reason for hiding this comment

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

Added some comments. Also, please note that the .DS_Store binary file that was added, needs to be removed, it does not belong in the repo.

Thank you!

django/contrib/sessions/backends/cached_db.py Outdated Show resolved Hide resolved
docs/topics/cache.txt Outdated Show resolved Hide resolved
@sulabhkatila
Copy link
Contributor Author

Hi @shangxiao, I have made the changes as discussed by moving the logger, update to the docs in the appropriate file, and removed the .DS_Store binary file.

Copy link
Contributor

@nessita nessita left a comment

Choose a reason for hiding this comment

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

As mentioned in one of the comments, a new logger needs to be defined and documented, and also the call to save() inside the try-except block should be moved outside that block.

Thank you for the work so far!

Copy link
Contributor

@nessita nessita left a comment

Choose a reason for hiding this comment

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

Hello @sulabhkatila, please read my last comment in full, there are still multiple things pending to implement, such as documenting the new logger and moving the save() call to outside the try-except block.

The documenting of the new logger needs to occur in multiple doc pages, I listed those in previous comments I think.

Please only when all those are ready, mark this PR as ready for review in the issue tracker as documented in https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/submitting-patches/#patch-review-checklist

@sulabhkatila
Copy link
Contributor Author

Hi @nessita , I apologize for the oversight.

Regarding the docs, I just added the release note about the behavior in docs/releases/5.0.txt.
Now, the docs related updates have been done on the following files: docs/releases/5.0.txt and docs/topics/cache.txt.
Is there any other pages in the docs that I might need to update?

Regarding the save call, initially I had put super().save(must_create()) call inside the try block, and after your feedback I figured I had to put that save call outside and I made the change. And now it looks as such:

 def save(self, must_create=False):
        super().save(must_create)
        try:
            self._cache.set(self.cache_key, self._session, self.get_expiry_age())
        except UpdateError:
            raise
        except Exception as e:
            logger.error("Error saving to cache: %s", e)

Is there some other save() calls that I were supposed to touch. Can you please provide more feedback on it.

Copy link
Contributor

@nessita nessita left a comment

Choose a reason for hiding this comment

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

Thank you @sulabhkatila for the updates.

Regarding your question:

Is there any other pages in the docs that I might need to update?


Yes, the logging docs also need updating (see docs/ref/logging.txt). Could you also please rebase onto main so you incorporate the latest changes from the main branch?

docs/releases/5.0.txt Outdated Show resolved Hide resolved
@sulabhkatila sulabhkatila marked this pull request as ready for review January 16, 2024 15:27
@nessita
Copy link
Contributor

nessita commented Feb 19, 2024

Hey @sulabhkatila, thank you for your continued work. If this branch is ready for a re-review, please double check that the ticket flags are properly set or unset. This are the docs describing those details.

@nessita
Copy link
Contributor

nessita commented Feb 21, 2024

@claudep Hi there! I pushed some code and docs tweaks, I think it's ready to be merged. Would you fancy doing a final review to this PR? (no worries if you can't!)

…ors.

Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Copy link
Member

@claudep claudep left a comment

Choose a reason for hiding this comment

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

Thanks a lot for working on this! We'll see in the future if other backend operations need some similar safeguards.

@nessita nessita merged commit eceb5e2 into django:main Feb 22, 2024
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants