Skip to content

Commit

Permalink
Implement retries in 'git-obs'
Browse files Browse the repository at this point in the history
  • Loading branch information
dmach committed Jan 15, 2025
1 parent 72ec3b2 commit 0cadbf8
Showing 1 changed file with 33 additions and 5 deletions.
38 changes: 33 additions & 5 deletions osc/gitea_api/connection.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import copy
import http.client
import json
import time
import urllib.parse
from typing import Optional

import urllib3
import urllib3.exceptions
import urllib3.response

from .conf import Login


# TODO: retry, backoff, connection pool?


class GiteaHTTPResponse:
"""
A ``urllib3.response.HTTPResponse`` wrapper
Expand Down Expand Up @@ -52,6 +51,16 @@ def __init__(self, login: Login, alternative_port: Optional[int] = None):
self.port = alternative_port if alternative_port else parsed_url.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"):
# needed to avoid: AttributeError: 'HTTPSConnection' object has no attribute 'assert_hostname'. Did you mean: 'server_hostname'?
self.conn.set_cert()
Expand Down Expand Up @@ -95,8 +104,27 @@ def request(self, method, url, json_data: Optional[dict] = None) -> GiteaHTTPRes

body = json.dumps(json_data) if json_data else None

self.conn.request(method, url, body, headers)
response = self.conn.getresponse()
for retry in range(1 + self.retry_count):
# 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):
result = GiteaHTTPResponse(urllib3.response.HTTPResponse.from_httplib(response))
Expand Down

0 comments on commit 0cadbf8

Please sign in to comment.