Skip to content

Commit 413dd16

Browse files
author
Clayton Walker
committed
fix: add 52x range to retry transient failures and tests
1 parent fc19da0 commit 413dd16

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

gitlab/client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ def http_request(
694694
)
695695
except requests.ConnectionError:
696696
if retry_transient_errors and (
697-
max_retries == -1 or cur_retries < max_retries
697+
max_retries == -1 or cur_retries < max_retries
698698
):
699699
wait_time = 2 ** cur_retries * 0.1
700700
cur_retries += 1
@@ -712,7 +712,11 @@ def http_request(
712712
"retry_transient_errors", self.retry_transient_errors
713713
)
714714
if (429 == result.status_code and obey_rate_limit) or (
715-
result.status_code in [500, 502, 503, 504] and retry_transient_errors
715+
(
716+
result.status_code in [500, 502, 503, 504]
717+
or 520 <= result.status_code <= 530
718+
)
719+
and retry_transient_errors
716720
):
717721
if max_retries == -1 or cur_retries < max_retries:
718722
wait_time = 2 ** cur_retries * 0.1

tests/unit/test_gitlab_http_methods.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def test_http_request_404(gl):
5151

5252

5353
@responses.activate
54-
@pytest.mark.parametrize("status_code", [500, 502, 503, 504])
54+
@pytest.mark.parametrize("status_code", [500, 502, 503, 504] + list(range(520, 530)))
5555
def test_http_request_with_only_failures(gl, status_code):
5656
url = "http://localhost/api/v4/projects"
5757
responses.add(
@@ -97,6 +97,37 @@ def request_callback(request):
9797
assert len(responses.calls) == calls_before_success
9898

9999

100+
@responses.activate
101+
def test_http_request_with_retry_on_method_for_transient_network_failures(gl):
102+
call_count = 0
103+
calls_before_success = 3
104+
105+
url = "http://localhost/api/v4/projects"
106+
107+
def request_callback(request):
108+
nonlocal call_count
109+
call_count += 1
110+
status_code = 200
111+
headers = {}
112+
body = "[]"
113+
114+
if call_count >= calls_before_success:
115+
return (status_code, headers, body)
116+
raise requests.ConnectionError("Connection aborted.")
117+
118+
responses.add_callback(
119+
method=responses.GET,
120+
url=url,
121+
callback=request_callback,
122+
content_type="application/json",
123+
)
124+
125+
http_r = gl.http_request("get", "/projects", retry_transient_errors=True)
126+
127+
assert http_r.status_code == 200
128+
assert len(responses.calls) == calls_before_success
129+
130+
100131
@responses.activate
101132
def test_http_request_with_retry_on_class_for_transient_failures(gl_retry):
102133
call_count = 0
@@ -126,6 +157,37 @@ def request_callback(request: requests.models.PreparedRequest):
126157
assert len(responses.calls) == calls_before_success
127158

128159

160+
@responses.activate
161+
def test_http_request_with_retry_on_class_for_transient_network_failures(gl_retry):
162+
call_count = 0
163+
calls_before_success = 3
164+
165+
url = "http://localhost/api/v4/projects"
166+
167+
def request_callback(request: requests.models.PreparedRequest):
168+
nonlocal call_count
169+
call_count += 1
170+
status_code = 200
171+
headers = {}
172+
body = "[]"
173+
174+
if call_count >= calls_before_success:
175+
return (status_code, headers, body)
176+
raise requests.ConnectionError("Connection aborted.")
177+
178+
responses.add_callback(
179+
method=responses.GET,
180+
url=url,
181+
callback=request_callback,
182+
content_type="application/json",
183+
)
184+
185+
http_r = gl_retry.http_request("get", "/projects", retry_transient_errors=True)
186+
187+
assert http_r.status_code == 200
188+
assert len(responses.calls) == calls_before_success
189+
190+
129191
@responses.activate
130192
def test_http_request_with_retry_on_class_and_method_for_transient_failures(gl_retry):
131193
call_count = 0
@@ -155,6 +217,39 @@ def request_callback(request):
155217
assert len(responses.calls) == 1
156218

157219

220+
@responses.activate
221+
def test_http_request_with_retry_on_class_and_method_for_transient_network_failures(
222+
gl_retry,
223+
):
224+
call_count = 0
225+
calls_before_success = 3
226+
227+
url = "http://localhost/api/v4/projects"
228+
229+
def request_callback(request):
230+
nonlocal call_count
231+
call_count += 1
232+
status_code = 200
233+
headers = {}
234+
body = "[]"
235+
236+
if call_count >= calls_before_success:
237+
return (status_code, headers, body)
238+
raise requests.ConnectionError("Connection aborted.")
239+
240+
responses.add_callback(
241+
method=responses.GET,
242+
url=url,
243+
callback=request_callback,
244+
content_type="application/json",
245+
)
246+
247+
with pytest.raises(requests.ConnectionError):
248+
gl_retry.http_request("get", "/projects", retry_transient_errors=False)
249+
250+
assert len(responses.calls) == 1
251+
252+
158253
def create_redirect_response(
159254
*, response: requests.models.Response, http_method: str, api_path: str
160255
) -> requests.models.Response:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy