Merge ~cjwatson/launchpad:tolerate-pymemcache-connection-errors into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 2ca35a803d834602daba35a973355aa938998788
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:tolerate-pymemcache-connection-errors
Merge into: launchpad:master
Diff against target: 88 lines (+36/-3)
2 files modified
lib/lp/services/memcache/client.py (+3/-3)
lib/lp/services/memcache/tests/test_memcache_client.py (+33/-0)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+412082@code.launchpad.net

Commit message

Tolerate connection errors from pymemcache as well

Description of the change

We should (log and) ignore connection errors from pymemcache for the same reason as `MemcacheError`: it's an opportunistic cache, and a failure shouldn't cause the code trying to use it to fail.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

🤞

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/services/memcache/client.py b/lib/lp/services/memcache/client.py
2index 2eb2b9a..69f7fd1 100644
3--- a/lib/lp/services/memcache/client.py
4+++ b/lib/lp/services/memcache/client.py
5@@ -33,7 +33,7 @@ class MemcacheClient(HashClient):
6 return super().get(key, default=None)
7 except MemcacheClientError:
8 raise
9- except MemcacheError as e:
10+ except (MemcacheError, OSError) as e:
11 if logger is not None:
12 logger.exception("Cannot get %s from memcached: %s" % (key, e))
13 return default
14@@ -44,7 +44,7 @@ class MemcacheClient(HashClient):
15 return super().set(key, value, expire=expire)
16 except MemcacheClientError:
17 raise
18- except MemcacheError as e:
19+ except (MemcacheError, OSError) as e:
20 if logger is not None:
21 logger.exception("Cannot set %s in memcached: %s" % (key, e))
22 return False
23@@ -55,7 +55,7 @@ class MemcacheClient(HashClient):
24 return super().delete(key)
25 except MemcacheClientError:
26 raise
27- except MemcacheError as e:
28+ except (MemcacheError, OSError) as e:
29 if logger is not None:
30 logger.exception(
31 "Cannot delete %s from memcached: %s" % (key, e))
32diff --git a/lib/lp/services/memcache/tests/test_memcache_client.py b/lib/lp/services/memcache/tests/test_memcache_client.py
33index 72400fe..5574d22 100644
34--- a/lib/lp/services/memcache/tests/test_memcache_client.py
35+++ b/lib/lp/services/memcache/tests/test_memcache_client.py
36@@ -66,6 +66,17 @@ class MemcacheClientTestCase(TestCase):
37 "ERROR Cannot get foo from memcached: All servers down\n",
38 logger.content.as_text())
39
40+ def test_get_connection_refused(self):
41+ logger = BufferLogger()
42+ with patch.object(self.client, "_get_client") as mock_get_client:
43+ mock_get_client.side_effect = ConnectionRefusedError(
44+ "Connection refused")
45+ self.assertIsNone(self.client.get("foo"))
46+ self.assertIsNone(self.client.get("foo", logger=logger))
47+ self.assertEqual(
48+ "ERROR Cannot get foo from memcached: Connection refused\n",
49+ logger.content.as_text())
50+
51 def test_set_failure(self):
52 logger = BufferLogger()
53 with patch.object(self.client, "_get_client") as mock_get_client:
54@@ -76,6 +87,17 @@ class MemcacheClientTestCase(TestCase):
55 "ERROR Cannot set foo in memcached: All servers down\n",
56 logger.content.as_text())
57
58+ def test_set_connection_refused(self):
59+ logger = BufferLogger()
60+ with patch.object(self.client, "_get_client") as mock_get_client:
61+ mock_get_client.side_effect = ConnectionRefusedError(
62+ "Connection refused")
63+ self.assertFalse(self.client.set("foo", "bar"))
64+ self.assertFalse(self.client.set("foo", "bar", logger=logger))
65+ self.assertEqual(
66+ "ERROR Cannot set foo in memcached: Connection refused\n",
67+ logger.content.as_text())
68+
69 def test_delete_failure(self):
70 logger = BufferLogger()
71 with patch.object(self.client, "_get_client") as mock_get_client:
72@@ -86,6 +108,17 @@ class MemcacheClientTestCase(TestCase):
73 "ERROR Cannot delete foo from memcached: All servers down\n",
74 logger.content.as_text())
75
76+ def test_delete_connection_refused(self):
77+ logger = BufferLogger()
78+ with patch.object(self.client, "_get_client") as mock_get_client:
79+ mock_get_client.side_effect = ConnectionRefusedError(
80+ "Connection refused")
81+ self.assertFalse(self.client.delete("foo"))
82+ self.assertFalse(self.client.delete("foo", logger=logger))
83+ self.assertEqual(
84+ "ERROR Cannot delete foo from memcached: Connection refused\n",
85+ logger.content.as_text())
86+
87
88 class MemcacheClientFactoryTestCase(TestCase):
89

Subscribers

People subscribed via source and target branches

to status/vote changes: