Created
September 15, 2018 05:41
-
-
Save aputs/ecfa285199e202be8ad79d5d2db8ddf1 to your computer and use it in GitHub Desktop.
add support for redis sentinel on django-redis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import logging | |
from django.conf import settings | |
from django.core.exceptions import ImproperlyConfigured | |
from redis.sentinel import Sentinel | |
from django_redis.client import DefaultClient | |
DJANGO_REDIS_LOGGER = getattr(settings, "DJANGO_REDIS_LOGGER", False) | |
DJANGO_REDIS_CLOSE_CONNECTION = getattr(settings, | |
"DJANGO_REDIS_CLOSE_CONNECTION", False) | |
class SentinelClient(DefaultClient): | |
""" | |
Sentinel client object extending django-redis DefaultClient | |
""" | |
def __init__(self, server, params, backend): | |
""" | |
Slightly different logic than connection to multiple Redis servers. | |
Reserve only one write and read descriptors, as they will be closed on exit anyway. | |
""" | |
super(SentinelClient, self).__init__(server, params, backend) | |
self._client = None | |
self._connection_string = server | |
self.log = logging.getLogger((DJANGO_REDIS_LOGGER or __name__)) | |
def parse_connection_string(self, constring): | |
""" | |
Parse connection string in format: | |
master_name/sentinel_server:port,sentinel_server:port/db_id | |
Returns master name, list of tuples with pair (host, port) and db_id | |
""" | |
try: | |
connection_params = constring.split('://') | |
if len(connection_params) > 1: | |
connection_params = connection_params[1].split('/') | |
master_name = connection_params[0] | |
servers = [ | |
host_port.split(':') | |
for host_port in connection_params[1].split(',') | |
] | |
sentinel_hosts = [(host, int(port)) for host, port in servers] | |
db = connection_params[2] | |
except (ValueError, TypeError, IndexError): | |
raise ImproperlyConfigured("Incorrect format '%s'" % (constring)) | |
return master_name, sentinel_hosts, db | |
def get_client(self, write=True, tried=(), show_index=False): | |
""" | |
Method used to obtain a raw redis client. | |
This function is used by almost all cache backend | |
operations to obtain a native redis client/connection | |
instance. | |
""" | |
if self._client is None: | |
self._client = self.connect() | |
if show_index: | |
return self._client, 0 | |
else: | |
return self._client | |
def connect(self, index=0): | |
""" | |
Creates a redis connection with connection pool. | |
""" | |
master_name, sentinel_hosts, db = self.parse_connection_string( | |
self._connection_string) | |
sentinel_timeout = self._options.get('SENTINEL_TIMEOUT', 1) | |
password = self._options.get('PASSWORD', None) | |
sentinel = Sentinel( | |
sentinel_hosts, socket_timeout=sentinel_timeout, password=password) | |
return sentinel.master_for( | |
master_name, | |
socket_timeout=sentinel_timeout, | |
db=db, | |
) | |
def close(self, **kwargs): | |
""" | |
Closing old connections, as master may change in time of inactivity. | |
""" | |
if DJANGO_REDIS_CLOSE_CONNECTION and self._client is not None: | |
del self._client |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment