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

New version 0.9.8 Redis URL Error #243

Closed
omarfateh0 opened this issue Mar 22, 2024 · 3 comments
Closed

New version 0.9.8 Redis URL Error #243

omarfateh0 opened this issue Mar 22, 2024 · 3 comments

Comments

@omarfateh0
Copy link

Hello,

I just upgraded to the new version 0.9.8 from version 0.9.7, and now I am facing this error
AttributeError: 'NoneType' object has no attribute 'startswith'

defender\utils.py", line 23, in
REDIS_SERVER = get_redis_connection()

defender\connection.py", line 35, in get_redis_connection
return redis.StrictRedis.from_url(config.DEFENDER_REDIS_URL)

redis\client.py", line 144, in from_url
connection_pool = ConnectionPool.from_url(url, **kwargs)

redis\connection.py", line 989, in from_url
url_options = parse_url(url)

redis\connection.py", line 879, in parse_url
url.startswith("redis://")

AttributeError: 'NoneType' object has no attribute 'startswith'

@kencochrane
Copy link
Collaborator

@omarfateh0, what do you have set for your DEFENDER_REDIS_URL config?

Also, which Redis library and version are you using?

@omarfateh0
Copy link
Author

omarfateh0 commented Mar 22, 2024

@kencochrane it works fine with version 0.9.7 with the same configurations , I didn't change anything
here are the libraries I am using:
django-redis==5.4.0
redis==5.0.3

and this defender redis url:
DEFENDER_REDIS_URL = f"redis://{REDIS_IP}:6379/0"

@kencochrane
Copy link
Collaborator

In the last release we removed a bunch of custom code to parse redis URLs and replaced it with the one built into the redis library. Probably related, but I'm not sure what is causing the issue.

Use redis parse_url method instead of a custom one (#234) [@dkr-sahar]

I tried to re-produce without Defender and it parses fine. And I'm able to re-produce your error by passing in a None value to redis.StrictRedis.from_url()

>>> REDIS_IP="127.0.0.1"
>>> DEFENDER_REDIS_URL = f"redis://{REDIS_IP}:6379/0"
>>> redis.StrictRedis.from_url(DEFENDER_REDIS_URL)
Redis<ConnectionPool<Connection<host=127.0.0.1,port=6379,db=0>>>

>>> redis.StrictRedis.from_url(None)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    redis.StrictRedis.from_url(None)
  File "/usr/local/lib/python3.11/site-packages/redis/client.py", line 144, in from_url
    connection_pool = ConnectionPool.from_url(url, **kwargs)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/redis/connection.py", line 989, in from_url
    url_options = parse_url(url)
                  ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/redis/connection.py", line 879, in parse_url
    url.startswith("redis://")
    ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'startswith'

The code is very simple:

https://github.com/jazzband/django-defender/blob/master/defender/connection.py#L16C1-L35C69

def get_redis_connection():
    """ Get the redis connection if not using mock """
    if config.MOCK_REDIS:  # pragma: no cover
        import mockredis

        return mockredis.mock_strict_redis_client()  # pragma: no cover
    elif config.DEFENDER_REDIS_NAME:  # pragma: no cover
        try:
            cache = caches[config.DEFENDER_REDIS_NAME]
        except InvalidCacheBackendError:
            raise KeyError(INVALID_CACHE_ERROR_MSG.format(config.DEFENDER_REDIS_NAME))
        # every redis backend implement it own way to get the low level client
        try:
            # redis_cache.RedisCache case (django-redis-cache package)
            return cache.get_master_client()
        except AttributeError:
            # django_redis.cache.RedisCache case (django-redis package)
            return cache.client.get_client(True)
    else:  # pragma: no cover)
        return redis.StrictRedis.from_url(config.DEFENDER_REDIS_URL)

we care about these lines here:

    else:  # pragma: no cover)
        return redis.StrictRedis.from_url(config.DEFENDER_REDIS_URL)

It takes the value from config.DEFENDER_REDIS_URL which is basically the DEFENDER_REDIS_URL settings variable and if your setting isn't None, I'm not sure what is going on.

What am I missing?

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

No branches or pull requests

2 participants