Igor Ciganovic
Igor Ciganovic

Reputation: 101

django-websocket-redis redis connection using unix socket

I'm using django-websocket-redis and have this in my settings.py:

WS4REDIS_CONNECTION = {
    'host': 'unix://var/run/redis/redis.sock',
    'db': 0,
    # 'port': 16379,
    # 'password': 'verysecret',
}

I tried all possible combinations of 'host' parameter and can't get it to connect using unix socket instead of tcp. I always get this message:

ConnectionError: Error -2 connecting to /var/run/redis/redis.sock:6379. Name or service not known.

Is there a way to connect ws4redis from django to redis using unix socket? If there is, how?

Upvotes: 1

Views: 802

Answers (1)

paulus
paulus

Reputation: 655

TL;DR: you have to override default Redis connection settings of ws4redis

I've bumped into this when I was implementing custom Django command, which was supposed to send a websocket message on certain server-side events.

If you look at the source code of RedisPublisher class, you will notice this line at the very top:

redis_connection_pool = ConnectionPool(**settings.WS4REDIS_CONNECTION)

while comments for ConnectionPool.__init__() state following:

By default, TCP connections are created connection_class is specified. Use redis.UnixDomainSocketConnection for unix sockets.

So when you're instantiating RedisPublisher it uses ConnectionPool which, by default, does not know anything about sockets. Therefore 2 approaches are possible:

  1. Switch default Connection to UnixDomainSocketConnection in ConnectionPool instantiation or
  2. Substitute ConnectionPool with StrictRedis connection which has built-in capabilities to use unix socket (named argument unix_socket_path).

This is how I solved it using 2nd approach (it appears cleaner for me):

from redis import StrictRedis
from django.conf import settings
from ws4redis.publisher import RedisPublisher
from ws4redis.redis_store import RedisMessage

r = StrictRedis(**settings.WS4REDIS_CONNECTION)
publisher = RedisPublisher(facility='foobar', broadcast=True)
publisher._connection = r
msg = RedisMessage('ping')
publisher.publish_message(msg)

The whole magic is in publisher._connection line which ultimately switches connection, used by RedisPublisher class. Since _connection assumes protected access, this looks like a bit dirty, but working solution.

You also need to specify following WS4REDIS_CONNECTION settings:

WS4REDIS_CONNECTION = {
    'unix_socket_path': '/tmp/redis.sock'
}

This is required for wsgi, since it appears to use built-in redis.py capability to connect to unix socket as it stated in docs

Upvotes: 1

Related Questions