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)