Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0353bd4

Browse files
authored
Merge pull request#1904 from Sineaggi/retry-additional-http-transient-errors
Retry additional http transient errors
2 parents19ab07d +5cbbf26 commit0353bd4

File tree

2 files changed

+126
-16
lines changed

2 files changed

+126
-16
lines changed

‎gitlab/client.py‎

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
"{source!r} to {target!r}"
3636
)
3737

38+
RETRYABLE_TRANSIENT_ERROR_CODES= [500,502,503,504]+list(range(520,531))
39+
3840

3941
classGitlab:
4042
"""Represents a GitLab server connection.
@@ -675,30 +677,42 @@ def http_request(
675677
json,data,content_type=self._prepare_send_data(files,post_data,raw)
676678
opts["headers"]["Content-type"]=content_type
677679

680+
retry_transient_errors=kwargs.get(
681+
"retry_transient_errors",self.retry_transient_errors
682+
)
678683
cur_retries=0
679684
whileTrue:
680-
result=self.session.request(
681-
method=verb,
682-
url=url,
683-
json=json,
684-
data=data,
685-
params=params,
686-
timeout=timeout,
687-
verify=verify,
688-
stream=streamed,
689-
**opts,
690-
)
685+
try:
686+
result=self.session.request(
687+
method=verb,
688+
url=url,
689+
json=json,
690+
data=data,
691+
params=params,
692+
timeout=timeout,
693+
verify=verify,
694+
stream=streamed,
695+
**opts,
696+
)
697+
exceptrequests.ConnectionError:
698+
ifretry_transient_errorsand (
699+
max_retries==-1orcur_retries<max_retries
700+
):
701+
wait_time=2**cur_retries*0.1
702+
cur_retries+=1
703+
time.sleep(wait_time)
704+
continue
705+
706+
raise
691707

692708
self._check_redirects(result)
693709

694710
if200<=result.status_code<300:
695711
returnresult
696712

697-
retry_transient_errors=kwargs.get(
698-
"retry_transient_errors",self.retry_transient_errors
699-
)
700713
if (429==result.status_codeandobey_rate_limit)or (
701-
result.status_codein [500,502,503,504]andretry_transient_errors
714+
result.status_codeinRETRYABLE_TRANSIENT_ERROR_CODES
715+
andretry_transient_errors
702716
):
703717
# Response headers documentation:
704718
# https://docs.gitlab.com/ee/user/admin_area/settings/user_and_ip_rate_limits.html#response-headers

‎tests/unit/test_gitlab_http_methods.py‎

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
importresponses
44

55
fromgitlabimportGitlabHttpError,GitlabList,GitlabParsingError,RedirectError
6+
fromgitlab.clientimportRETRYABLE_TRANSIENT_ERROR_CODES
67
fromtests.unitimporthelpers
78

89
MATCH_EMPTY_QUERY_PARAMS= [responses.matchers.query_param_matcher({})]
@@ -51,7 +52,7 @@ def test_http_request_404(gl):
5152

5253

5354
@responses.activate
54-
@pytest.mark.parametrize("status_code",[500,502,503,504])
55+
@pytest.mark.parametrize("status_code",RETRYABLE_TRANSIENT_ERROR_CODES)
5556
deftest_http_request_with_only_failures(gl,status_code):
5657
url="http://localhost/api/v4/projects"
5758
responses.add(
@@ -97,6 +98,37 @@ def request_callback(request):
9798
assertlen(responses.calls)==calls_before_success
9899

99100

101+
@responses.activate
102+
deftest_http_request_with_retry_on_method_for_transient_network_failures(gl):
103+
call_count=0
104+
calls_before_success=3
105+
106+
url="http://localhost/api/v4/projects"
107+
108+
defrequest_callback(request):
109+
nonlocalcall_count
110+
call_count+=1
111+
status_code=200
112+
headers= {}
113+
body="[]"
114+
115+
ifcall_count>=calls_before_success:
116+
return (status_code,headers,body)
117+
raiserequests.ConnectionError("Connection aborted.")
118+
119+
responses.add_callback(
120+
method=responses.GET,
121+
url=url,
122+
callback=request_callback,
123+
content_type="application/json",
124+
)
125+
126+
http_r=gl.http_request("get","/projects",retry_transient_errors=True)
127+
128+
asserthttp_r.status_code==200
129+
assertlen(responses.calls)==calls_before_success
130+
131+
100132
@responses.activate
101133
deftest_http_request_with_retry_on_class_for_transient_failures(gl_retry):
102134
call_count=0
@@ -126,6 +158,37 @@ def request_callback(request: requests.models.PreparedRequest):
126158
assertlen(responses.calls)==calls_before_success
127159

128160

161+
@responses.activate
162+
deftest_http_request_with_retry_on_class_for_transient_network_failures(gl_retry):
163+
call_count=0
164+
calls_before_success=3
165+
166+
url="http://localhost/api/v4/projects"
167+
168+
defrequest_callback(request:requests.models.PreparedRequest):
169+
nonlocalcall_count
170+
call_count+=1
171+
status_code=200
172+
headers= {}
173+
body="[]"
174+
175+
ifcall_count>=calls_before_success:
176+
return (status_code,headers,body)
177+
raiserequests.ConnectionError("Connection aborted.")
178+
179+
responses.add_callback(
180+
method=responses.GET,
181+
url=url,
182+
callback=request_callback,
183+
content_type="application/json",
184+
)
185+
186+
http_r=gl_retry.http_request("get","/projects",retry_transient_errors=True)
187+
188+
asserthttp_r.status_code==200
189+
assertlen(responses.calls)==calls_before_success
190+
191+
129192
@responses.activate
130193
deftest_http_request_with_retry_on_class_and_method_for_transient_failures(gl_retry):
131194
call_count=0
@@ -155,6 +218,39 @@ def request_callback(request):
155218
assertlen(responses.calls)==1
156219

157220

221+
@responses.activate
222+
deftest_http_request_with_retry_on_class_and_method_for_transient_network_failures(
223+
gl_retry,
224+
):
225+
call_count=0
226+
calls_before_success=3
227+
228+
url="http://localhost/api/v4/projects"
229+
230+
defrequest_callback(request):
231+
nonlocalcall_count
232+
call_count+=1
233+
status_code=200
234+
headers= {}
235+
body="[]"
236+
237+
ifcall_count>=calls_before_success:
238+
return (status_code,headers,body)
239+
raiserequests.ConnectionError("Connection aborted.")
240+
241+
responses.add_callback(
242+
method=responses.GET,
243+
url=url,
244+
callback=request_callback,
245+
content_type="application/json",
246+
)
247+
248+
withpytest.raises(requests.ConnectionError):
249+
gl_retry.http_request("get","/projects",retry_transient_errors=False)
250+
251+
assertlen(responses.calls)==1
252+
253+
158254
defcreate_redirect_response(
159255
*,response:requests.models.Response,http_method:str,api_path:str
160256
)->requests.models.Response:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp