summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Anderson <sontek@gmail.com>2015-07-02 15:38:43 -0700
committerJohn Anderson <sontek@gmail.com>2015-07-02 15:38:43 -0700
commitb7c02a3c2d29e4d017c78d9525a96da8a2aacb0f (patch)
tree489a28f4ee4b7ee91938b6f2fb87d526d4bb9adc
parentd6fc5ce0edeffe5f89d814c7b21ef57d76529662 (diff)
downloadpymemcache-b7c02a3c2d29e4d017c78d9525a96da8a2aacb0f.tar.gz
Make ignoring exceptions optional
-rw-r--r--pymemcache/client/hash.py52
-rw-r--r--pymemcache/test/test_client_hash.py44
2 files changed, 76 insertions, 20 deletions
diff --git a/pymemcache/client/hash.py b/pymemcache/client/hash.py
index 8a79672..7ef0710 100644
--- a/pymemcache/client/hash.py
+++ b/pymemcache/client/hash.py
@@ -29,6 +29,7 @@ class HashClient(object):
retry_timeout=1,
dead_timeout=60,
use_pooling=False,
+ ignore_exc=False,
):
"""
Constructor.
@@ -64,6 +65,7 @@ class HashClient(object):
self.dead_timeout = dead_timeout
self.use_pooling = use_pooling
self.key_prefix = key_prefix
+ self.ignore_exc = ignore_exc
self._failed_clients = {}
self._dead_clients = {}
self._last_dead_check_time = time.time()
@@ -132,7 +134,7 @@ class HashClient(object):
client = self.clients[server]
return client
- def _safely_run_func(self, client, func, *args, **kwargs):
+ def _safely_run_func(self, client, func, default_val, *args, **kwargs):
try:
if client.server in self._failed_clients:
# This server is currently failing, lets check if it is in
@@ -152,7 +154,7 @@ class HashClient(object):
# clients
self._failed_clients.pop(client.server)
return result
- return
+ return default_val
else:
# We've reached our max retry attempts, we need to mark
# the sever as dead
@@ -194,24 +196,38 @@ class HashClient(object):
failed_metadata['failed_time'] = time.time()
self._failed_clients[client.server] = failed_metadata
- def _run_cmd(self, cmd, key, *args, **kwargs):
+ # if we haven't enabled ignore_exc, don't move on gracefully, just
+ # raise the exception
+ if not self.ignore_exc:
+ raise
+
+ return default_val
+ except:
+ # any exceptions that aren't socket.error we need to handle
+ # gracefully as well
+ if not self.ignore_exc:
+ raise
+
+ return default_val
+
+ def _run_cmd(self, cmd, key, default_val, *args, **kwargs):
client = self._get_client(key)
func = getattr(client, cmd)
args = list(args)
args.insert(0, key)
- return self._safely_run_func(client, func, *args, **kwargs)
+ return self._safely_run_func(client, func, default_val, *args, **kwargs)
def set(self, key, *args, **kwargs):
- return self._run_cmd('set', key, *args, **kwargs)
+ return self._run_cmd('set', key, False, *args, **kwargs)
def get(self, key, *args, **kwargs):
- return self._run_cmd('get', key, *args, **kwargs)
+ return self._run_cmd('get', key, None, *args, **kwargs)
def incr(self, key, *args, **kwargs):
- return self._run_cmd('incr', key, *args, **kwargs)
+ return self._run_cmd('incr', key, False, *args, **kwargs)
def decr(self, key, *args, **kwargs):
- return self._run_cmd('decr', key, *args, **kwargs)
+ return self._run_cmd('decr', key, False, *args, **kwargs)
def set_many(self, values, *args, **kwargs):
client_batches = {}
@@ -230,7 +246,7 @@ class HashClient(object):
new_args.insert(0, values)
result = self._safely_run_func(
client,
- client.set_many, *new_args, **kwargs
+ client.set_many, False, *new_args, **kwargs
)
end.append(result)
@@ -253,33 +269,33 @@ class HashClient(object):
new_args.insert(0, keys)
result = self._safely_run_func(
client,
- client.get_many, *new_args, **kwargs
+ client.get_many, {}, *new_args, **kwargs
)
end.update(result)
return end
def gets(self, key, *args, **kwargs):
- return self._run_cmd('gets', key, *args, **kwargs)
+ return self._run_cmd('gets', key, None, *args, **kwargs)
def add(self, key, *args, **kwargs):
- return self._run_cmd('add', key, *args, **kwargs)
+ return self._run_cmd('add', key, False, *args, **kwargs)
def prepend(self, key, *args, **kwargs):
- return self._run_cmd('prepend', key, *args, **kwargs)
+ return self._run_cmd('prepend', key, False, *args, **kwargs)
def append(self, key, *args, **kwargs):
- return self._run_cmd('append', key, *args, **kwargs)
+ return self._run_cmd('append', key, False, *args, **kwargs)
def delete(self, key, *args, **kwargs):
- return self._run_cmd('delete', key, *args, **kwargs)
+ return self._run_cmd('delete', key, False, *args, **kwargs)
def cas(self, key, *args, **kwargs):
- return self._run_cmd('cas', key, *args, **kwargs)
+ return self._run_cmd('cas', key, False, *args, **kwargs)
def replace(self, key, *args, **kwargs):
- return self._run_cmd('replace', key, *args, **kwargs)
+ return self._run_cmd('replace', key, False, *args, **kwargs)
def flush_all(self):
for _, client in self.clients.items():
- self._safely_run_func(client, client.flush_all)
+ self._safely_run_func(client, client.flush_all, False)
diff --git a/pymemcache/test/test_client_hash.py b/pymemcache/test/test_client_hash.py
index 27b88ca..5cd6cef 100644
--- a/pymemcache/test/test_client_hash.py
+++ b/pymemcache/test/test_client_hash.py
@@ -1,9 +1,11 @@
from pymemcache.client.hash import HashClient
from pymemcache.client.base import Client, PooledClient
+from pymemcache.exceptions import MemcacheUnknownError
from pymemcache import pool
from .test_client import ClientTestMixin, MockSocket
import unittest
+import pytest
class TestHashClient(ClientTestMixin, unittest.TestCase):
@@ -15,10 +17,11 @@ class TestHashClient(ClientTestMixin, unittest.TestCase):
client.client_pool = pool.ObjectPool(lambda: mock_client)
return mock_client
- def make_client(self, *mock_socket_values):
+ def make_client(self, *mock_socket_values, **kwargs):
current_port = 11012
- client = HashClient([])
+ client = HashClient([], **kwargs)
ip = '127.0.0.1'
+
for vals in mock_socket_values:
s = '%s:%s' % (ip, current_port)
c = self.make_client_pool(
@@ -68,4 +71,41 @@ class TestHashClient(ClientTestMixin, unittest.TestCase):
assert result == {b'key1': b'value1'}
+ def test_get_many_bad_server_data(self):
+ client = self.make_client(*[
+ [b'STORED\r\n', b'VAXLUE key3 0 6\r\nvalue2\r\nEND\r\n', ],
+ [b'STORED\r\n', b'VAXLUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
+ ])
+
+ def get_clients(key):
+ if key == b'key3':
+ return client.clients['127.0.0.1:11012']
+ else:
+ return client.clients['127.0.0.1:11013']
+
+ client._get_client = get_clients
+
+ with pytest.raises(MemcacheUnknownError):
+ result = client.set(b'key1', b'value1', noreply=False)
+ result = client.set(b'key3', b'value2', noreply=False)
+ result = client.get_many([b'key1', b'key3'])
+
+ def test_get_many_bad_server_data_ignore(self):
+ client = self.make_client(*[
+ [b'STORED\r\n', b'VAXLUE key3 0 6\r\nvalue2\r\nEND\r\n', ],
+ [b'STORED\r\n', b'VAXLUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
+ ], ignore_exc=True)
+
+ def get_clients(key):
+ if key == b'key3':
+ return client.clients['127.0.0.1:11012']
+ else:
+ return client.clients['127.0.0.1:11013']
+
+ client._get_client = get_clients
+
+ result = client.set(b'key1', b'value1', noreply=False)
+ result = client.set(b'key3', b'value2', noreply=False)
+ result = client.get_many([b'key1', b'key3'])
+ assert result == {}
# TODO: Test failover logic