Skip to content

Infinite loop and memory leak caused by the omit_exceptions decorator #658

Open
@HosseyNJF

Description

@HosseyNJF

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:

  1. Stop the Redis server.
  2. Set DEBUG = True and DJANGO_REDIS_IGNORE_EXCEPTIONS = False.
  3. Try to access the cache in any view.
  4. 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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions