Skip to content

Commit 9e199ba

Browse files
authored
Merge pull request gusdan#8 from uncovertruth/feature/ignore_cluster_info_error
Feature/ignore cluster info error
2 parents d25f3ce + f4e8c7c commit 9e199ba

File tree

5 files changed

+38
-38
lines changed

5 files changed

+38
-38
lines changed

README.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ Your cache backend should look something like this::
4848
CACHES = {
4949
'default': {
5050
'BACKEND': 'django_elastipymemcache.memcached.ElastiPyMemCache',
51-
'LOCATION': '[configuration endpoint].com:11211',
51+
'LOCATION': '[configuration endpoint]:11211',
52+
'OPTIONS': {
53+
'cluster_timeout': 1, # its used when get cluster info
54+
'ignore_exc': True, # pymemcache Client params
55+
}
5256
}
5357
}
5458

django_elastipymemcache/cluster_utils.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import re
55
from distutils.version import StrictVersion
6+
import socket
67
from telnetlib import Telnet
78

89
from django.utils.encoding import smart_text
@@ -18,7 +19,7 @@ def __init__(self, cmd, response):
1819
'Unexpected response {} for command {}'.format(response, cmd))
1920

2021

21-
def get_cluster_info(host, port, ignore_cluster_errors=False):
22+
def get_cluster_info(host, port, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
2223
"""
2324
return dict with info about nodes in cluster and current version
2425
{
@@ -29,7 +30,7 @@ def get_cluster_info(host, port, ignore_cluster_errors=False):
2930
'version': '1.4.4'
3031
}
3132
"""
32-
client = Telnet(host, int(port))
33+
client = Telnet(host, int(port), timeout=timeout)
3334
client.write(b'version\n')
3435
res = client.read_until(b'\r\n').strip()
3536
version_list = res.split(b' ')
@@ -47,14 +48,6 @@ def get_cluster_info(host, port, ignore_cluster_errors=False):
4748
])
4849
client.close()
4950

50-
if res == b'ERROR\r\n' and ignore_cluster_errors:
51-
return {
52-
'version': version,
53-
'nodes': [
54-
(smart_text(host), int(port))
55-
]
56-
}
57-
5851
ls = list(filter(None, re.compile(br'\r?\n').split(res)))
5952
if len(ls) != 4:
6053
raise WrongProtocolData(cmd, res)

django_elastipymemcache/memcached.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Backend for django cache
33
"""
4+
import logging
45
import socket
56
from functools import wraps
67

@@ -11,6 +12,9 @@
1112
from .cluster_utils import get_cluster_info
1213

1314

15+
logger = logging.getLogger(__name__)
16+
17+
1418
def invalidate_cache_after_error(f):
1519
"""
1620
catch any exception and invalidate internal cache with list of nodes
@@ -46,8 +50,8 @@ def __init__(self, server, params):
4650

4751
# Patch for django<1.11
4852
self._options = self._options or dict()
49-
self._ignore_cluster_errors = self._options.get(
50-
'ignore_exc', False)
53+
self._cluster_timeout = self._options.get(
54+
'cluster_timeout', socket._GLOBAL_DEFAULT_TIMEOUT)
5155

5256
def clear_cluster_nodes_cache(self):
5357
"""clear internal cache with list of nodes in cluster"""
@@ -63,18 +67,28 @@ def get_cluster_nodes(self):
6367
return get_cluster_info(
6468
server,
6569
port,
66-
self._ignore_cluster_errors
70+
self._cluster_timeout
6771
)['nodes']
68-
except (socket.gaierror, socket.timeout) as err:
69-
raise Exception('Cannot connect to cluster {} ({})'.format(
70-
self._servers[0], err
71-
))
72+
except (OSError, socket.gaierror, socket.timeout) as err:
73+
logger.debug(
74+
'Cannot connect to cluster %s, err: %s',
75+
self._servers[0],
76+
err
77+
)
78+
return []
7279

7380
@property
7481
def _cache(self):
82+
7583
if getattr(self, '_client', None) is None:
84+
85+
options = self._options
86+
options.setdefault('ignore_exc', True)
87+
options.pop('cluster_timeout', None)
88+
7689
self._client = self._lib.Client(
77-
self.get_cluster_nodes(), **self._options)
90+
self.get_cluster_nodes(), **options)
91+
7892
return self._client
7993

8094
@invalidate_cache_after_error

tests/test_backend.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import socket
12
import sys
23

34
from django.conf import global_settings, settings
@@ -25,8 +26,9 @@ def test_split_servers(get_cluster_info):
2526
}
2627
backend._lib.Client = Mock()
2728
assert backend._cache
28-
get_cluster_info.assert_called_once_with('h', '0', False)
29-
backend._lib.Client.assert_called_once_with(servers)
29+
get_cluster_info.assert_called_once_with(
30+
'h', '0', socket._GLOBAL_DEFAULT_TIMEOUT)
31+
backend._lib.Client.assert_called_once_with(servers, ignore_exc=True)
3032

3133

3234
@patch('django.conf.settings', global_settings)
@@ -44,11 +46,12 @@ def test_node_info_cache(get_cluster_info):
4446
backend.get('key1')
4547
backend.set('key2', 'val')
4648
backend.get('key2')
47-
backend._lib.Client.assert_called_once_with(servers)
49+
backend._lib.Client.assert_called_once_with(servers, ignore_exc=True)
4850
eq_(backend._cache.get.call_count, 2)
4951
eq_(backend._cache.set.call_count, 2)
5052

51-
get_cluster_info.assert_called_once_with('h', '0', False)
53+
get_cluster_info.assert_called_once_with(
54+
'h', '0', socket._GLOBAL_DEFAULT_TIMEOUT)
5255

5356

5457
@patch('django.conf.settings', global_settings)

tests/test_protocol.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,27 +103,13 @@ def test_ubuntu_protocol(Telnet):
103103
])
104104

105105

106-
@patch('django_elastipymemcache.cluster_utils.Telnet')
107-
def test_no_configuration_protocol_support_with_errors_ignored(Telnet):
108-
client = Telnet.return_value
109-
client.read_until.side_effect = TEST_PROTOCOL_4_READ_UNTIL
110-
client.expect.side_effect = TEST_PROTOCOL_4_EXPECT
111-
info = get_cluster_info('test', 0, ignore_cluster_errors=True)
112-
client.write.assert_has_calls([
113-
call(b'version\n'),
114-
call(b'config get cluster\n'),
115-
])
116-
eq_(info['version'], b'1.4.34')
117-
eq_(info['nodes'], [('test', 0)])
118-
119-
120106
@raises(WrongProtocolData)
121107
@patch('django_elastipymemcache.cluster_utils.Telnet')
122108
def test_no_configuration_protocol_support_with_errors(Telnet):
123109
client = Telnet.return_value
124110
client.read_until.side_effect = TEST_PROTOCOL_4_READ_UNTIL
125111
client.expect.side_effect = TEST_PROTOCOL_4_EXPECT
126-
get_cluster_info('test', 0, ignore_cluster_errors=False)
112+
get_cluster_info('test', 0)
127113
client.write.assert_has_calls([
128114
call(b'version\n'),
129115
call(b'config get cluster\n'),

0 commit comments

Comments
 (0)