Skip to content

Commit 71599b9

Browse files
authored
Retry on 500 (#168)
* workaround: retry manifest upload on quay * decorator: get rid of inheritance * decorator: retry on 500 Signed-off-by: Isabella do Amaral <[email protected]>
1 parent ff9c2e2 commit 71599b9

File tree

4 files changed

+22
-47
lines changed

4 files changed

+22
-47
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and **Merged pull requests**. Critical items to know are:
1414
The versions coincide with releases on pip. Only major versions will be released as tags on Github.
1515

1616
## [0.0.x](https://github.com/oras-project/oras-py/tree/main) (0.0.x)
17+
- retry on 500 (0.2.25)
1718
- align provider config_path type annotations (0.2.24)
1819
- add missing prefix property to auth backend (0.2.23)
1920
- allow for filepaths to include `:` (0.2.22)

oras/decorator.py

+19-45
Original file line numberDiff line numberDiff line change
@@ -3,77 +3,51 @@
33
__license__ = "Apache-2.0"
44

55
import time
6-
from functools import partial, update_wrapper
6+
from functools import wraps
77

88
import oras.auth
99
from oras.logger import logger
1010

1111

12-
class Decorator:
13-
"""
14-
Shared parent decorator class
15-
"""
16-
17-
def __init__(self, func):
18-
update_wrapper(self, func)
19-
self.func = func
20-
21-
def __get__(self, obj, objtype):
22-
return partial(self.__call__, obj)
23-
24-
25-
class ensure_container(Decorator):
12+
def ensure_container(func):
2613
"""
2714
Ensure the first argument is a container, and not a string.
2815
"""
2916

30-
def __call__(self, cls, *args, **kwargs):
17+
@wraps(func)
18+
def wrapper(cls, *args, **kwargs):
3119
if "container" in kwargs:
3220
kwargs["container"] = cls.get_container(kwargs["container"])
3321
elif args:
3422
container = cls.get_container(args[0])
3523
args = (container, *args[1:])
36-
return self.func(cls, *args, **kwargs)
37-
38-
39-
class classretry(Decorator):
40-
"""
41-
Retry a function that is part of a class
42-
"""
43-
44-
def __init__(self, func, attempts=5, timeout=2):
45-
super().__init__(func)
46-
self.attempts = attempts
47-
self.timeout = timeout
24+
return func(cls, *args, **kwargs)
4825

49-
def __call__(self, cls, *args, **kwargs):
50-
attempt = 0
51-
attempts = self.attempts
52-
timeout = self.timeout
53-
while attempt < attempts:
54-
try:
55-
return self.func(cls, *args, **kwargs)
56-
except oras.auth.AuthenticationException as e:
57-
raise e
58-
except Exception as e:
59-
sleep = timeout + 3**attempt
60-
logger.info(f"Retrying in {sleep} seconds - error: {e}")
61-
time.sleep(sleep)
62-
attempt += 1
63-
return self.func(cls, *args, **kwargs)
26+
return wrapper
6427

6528

66-
def retry(attempts, timeout=2):
29+
def retry(attempts=5, timeout=2):
6730
"""
6831
A simple retry decorator
6932
"""
7033

7134
def decorator(func):
35+
@wraps(func)
7236
def inner(*args, **kwargs):
7337
attempt = 0
7438
while attempt < attempts:
7539
try:
76-
return func(*args, **kwargs)
40+
res = func(*args, **kwargs)
41+
if res.status_code == 500:
42+
try:
43+
msg = res.json()
44+
for error in msg.get("errors", []):
45+
if isinstance(error, dict) and "message" in error:
46+
logger.error(error["message"])
47+
except Exception:
48+
pass
49+
raise ValueError(f"Issue with {res.request.url}: {res.reason}")
50+
return res
7751
except oras.auth.AuthenticationException as e:
7852
raise e
7953
except Exception as e:

oras/provider.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ def get_manifest(
935935
jsonschema.validate(manifest, schema=oras.schemas.manifest)
936936
return manifest
937937

938-
@decorator.classretry
938+
@decorator.retry()
939939
def do_request(
940940
self,
941941
url: str,

oras/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
__copyright__ = "Copyright The ORAS Authors."
33
__license__ = "Apache-2.0"
44

5-
__version__ = "0.2.24"
5+
__version__ = "0.2.25"
66
AUTHOR = "Vanessa Sochat"
77
88
NAME = "oras"

0 commit comments

Comments
 (0)