summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClay Gerrard <clay.gerrard@gmail.com>2022-08-10 12:38:54 -0500
committerTim Burke <tim.burke@gmail.com>2022-08-18 12:14:04 -0700
commit653cbcb686fc34cc28f9c7889e8746e77b95371a (patch)
treedcaaeb0596aa7283b1863e77df3eeddfcb76530c
parenta1d2f31131d79d7c551dbac4fc1e9c4d177d2df5 (diff)
downloadpython-swiftclient-653cbcb686fc34cc28f9c7889e8746e77b95371a.tar.gz
Expand retry handling on ratelimit response
We have seen middlewares that return ratelimit responses as 498 or 429, so tolerate either. Closes-Bug: #1879572 Change-Id: I027222157f6c2ad7882a0508302c9de097baae4c
-rw-r--r--swiftclient/client.py2
-rw-r--r--test/unit/test_swiftclient.py54
2 files changed, 31 insertions, 25 deletions
diff --git a/swiftclient/client.py b/swiftclient/client.py
index 8415db2..16bbba8 100644
--- a/swiftclient/client.py
+++ b/swiftclient/client.py
@@ -1833,7 +1833,7 @@ class Connection:
self.http_conn = None
elif 500 <= err.http_status <= 599:
pass
- elif self.retry_on_ratelimit and err.http_status == 498:
+ elif self.retry_on_ratelimit and err.http_status in (498, 429):
pass
else:
raise
diff --git a/test/unit/test_swiftclient.py b/test/unit/test_swiftclient.py
index 436245d..ae3e76f 100644
--- a/test/unit/test_swiftclient.py
+++ b/test/unit/test_swiftclient.py
@@ -2130,31 +2130,37 @@ class TestConnection(MockHttpTest):
pass
c.sleep = quick_sleep
- # test retries
- conn = c.Connection('http://www.test.com/auth/v1.0', 'asdf', 'asdf',
- retry_on_ratelimit=True)
- code_iter = [200] + [498] * (conn.retries + 1)
- auth_resp_headers = {
- 'x-auth-token': 'asdf',
- 'x-storage-url': 'http://storage/v1/test',
- }
- c.http_connection = self.fake_http_connection(
- *code_iter, headers=auth_resp_headers)
- with self.assertRaises(c.ClientException) as exc_context:
- conn.head_account()
- self.assertIn('Account HEAD failed', str(exc_context.exception))
- self.assertEqual(conn.attempts, conn.retries + 1)
+ def test_status_code(code):
+ # test retries
+ conn = c.Connection('http://www.test.com/auth/v1.0',
+ 'asdf', 'asdf', retry_on_ratelimit=True)
+ code_iter = [200] + [code] * (conn.retries + 1)
+ auth_resp_headers = {
+ 'x-auth-token': 'asdf',
+ 'x-storage-url': 'http://storage/v1/test',
+ }
+ c.http_connection = self.fake_http_connection(
+ *code_iter, headers=auth_resp_headers)
+ with self.assertRaises(c.ClientException) as exc_context:
+ conn.head_account()
+ self.assertIn('Account HEAD failed', str(exc_context.exception))
+ self.assertEqual(code, exc_context.exception.http_status)
+ self.assertEqual(conn.attempts, conn.retries + 1)
- # test default no-retry
- c.http_connection = self.fake_http_connection(
- 200, 498,
- headers=auth_resp_headers)
- conn = c.Connection('http://www.test.com/auth/v1.0', 'asdf', 'asdf',
- retry_on_ratelimit=False)
- with self.assertRaises(c.ClientException) as exc_context:
- conn.head_account()
- self.assertIn('Account HEAD failed', str(exc_context.exception))
- self.assertEqual(conn.attempts, 1)
+ # test default no-retry
+ c.http_connection = self.fake_http_connection(
+ 200, code,
+ headers=auth_resp_headers)
+ conn = c.Connection('http://www.test.com/auth/v1.0',
+ 'asdf', 'asdf', retry_on_ratelimit=False)
+ with self.assertRaises(c.ClientException) as exc_context:
+ conn.head_account()
+ self.assertIn('Account HEAD failed', str(exc_context.exception))
+ self.assertEqual(code, exc_context.exception.http_status)
+ self.assertEqual(conn.attempts, 1)
+
+ test_status_code(498)
+ test_status_code(429)
def test_retry_with_socket_error(self):
def quick_sleep(*args):