1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-10-31 19:42:16 +01:00

Implement retries in 'git-obs'

This commit is contained in:
2025-01-15 09:13:48 +01:00
parent b938585cfb
commit 99dcb4e10a

View File

@@ -1,18 +1,17 @@
import copy import copy
import http.client import http.client
import json import json
import time
import urllib.parse import urllib.parse
from typing import Optional from typing import Optional
import urllib3 import urllib3
import urllib3.exceptions
import urllib3.response import urllib3.response
from .conf import Login from .conf import Login
# TODO: retry, backoff, connection pool?
class GiteaHTTPResponse: class GiteaHTTPResponse:
""" """
A ``urllib3.response.HTTPResponse`` wrapper A ``urllib3.response.HTTPResponse`` wrapper
@@ -52,6 +51,16 @@ class Connection:
self.port = alternative_port if alternative_port else parsed_url.port self.port = alternative_port if alternative_port else parsed_url.port
self.conn = ConnectionClass(host=self.host, port=self.port) self.conn = ConnectionClass(host=self.host, port=self.port)
# retries; variables are named according to urllib3
self.retry_count = 3
self.retry_backoff_factor = 2
self.retry_status_forcelist = (
500, # Internal Server Error
502, # Bad Gateway
503, # Service Unavailable
504, # Gateway Timeout
)
if hasattr(self.conn, "set_cert"): if hasattr(self.conn, "set_cert"):
# needed to avoid: AttributeError: 'HTTPSConnection' object has no attribute 'assert_hostname'. Did you mean: 'server_hostname'? # needed to avoid: AttributeError: 'HTTPSConnection' object has no attribute 'assert_hostname'. Did you mean: 'server_hostname'?
self.conn.set_cert() self.conn.set_cert()
@@ -95,8 +104,27 @@ class Connection:
body = json.dumps(json_data) if json_data else None body = json.dumps(json_data) if json_data else None
self.conn.request(method, url, body, headers) for retry in range(1 + self.retry_count):
response = self.conn.getresponse() # 1 regular request + ``self.retry_count`` retries
try:
self.conn.request(method, url, body, headers)
response = self.conn.getresponse()
if response.status not in self.retry_status_forcelist:
# we are happy with the response status -> use the response
break
if retry >= self.retry_count:
# we have reached maximum number of retries -> use the response
break
except (urllib3.exceptions.HTTPError, ConnectionResetError):
if retry >= self.retry_count:
raise
# {backoff factor} * (2 ** ({number of previous retries}))
time.sleep(self.retry_backoff_factor * (2 ** retry))
self.conn.close()
if isinstance(response, http.client.HTTPResponse): if isinstance(response, http.client.HTTPResponse):
result = GiteaHTTPResponse(urllib3.response.HTTPResponse.from_httplib(response)) result = GiteaHTTPResponse(urllib3.response.HTTPResponse.from_httplib(response))