Description
Describe the bug
When the Redis server is down, a ConnectionError
is raised. The omit_exceptions
decorator will check the ignore_exceptions settings and if it is set to False
, it will re-raise the __cause__
of the raised exception, which is a ConnectionInterruped
with a cause of redis.ConnectionError
. But somehow the __context__
of the redis error is equal to the ConnectionInterruped
exception itself. This causes an infinite loop in the django.views.debug.technical_500_response
method that tries to print the traceback but finds itself in a never-ending chain of causes and contexts.
To Reproduce
Steps to reproduce the behavior:
- Stop the Redis server.
- Set
DEBUG = True
andDJANGO_REDIS_IGNORE_EXCEPTIONS = False
. - Try to access the cache in any view.
- Watch as the process hangs and eventually gets OOM killed.
Expected behavior
I expected to simply see a ConnectionInterrupted
exception in my console and in my response because the connection failed.
Environment (please complete the following information):
- Python version: 3.9
- Django Redis Version: 5.2.0
- Django Version: 2.2
- redis Version: irrelevant
- redis-py Version: 4.5.1
Additional context
The problem only happens when Django's DEBUG = True
is set, as it will make Django try to print the traceback. Also, the DJANGO_REDIS_IGNORE_EXCEPTIONS
setting must be set to False
to force the omit_exceptions
decorator to re-raise the exception's __cause__
. The problem doesn't seem to happen when python itself is trying to print the traceback, and I don't know why. Maybe they expected someone to raise a circular exception and had measures for that?