Skip to content

Commit 2ddc926

Browse files
authored
Merge pull request #177 from acsone/duck-fetch-errors
Retry on git fetch errors
2 parents b99079c + ef2f09b commit 2ddc926

File tree

5 files changed

+98
-2
lines changed

5 files changed

+98
-2
lines changed

newsfragments/177.bugfix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Try to avoid git fetch lock issues and sentry alerts pollution by retrying
2+
automatically.

src/oca_github_bot/github.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) ACSONE SA/NV 2018-2019
22
# Distributed under the MIT License (http://opensource.org/licenses/MIT).
33

4+
import functools
45
import logging
56
import os
67
import shutil
@@ -13,6 +14,7 @@
1314

1415
from . import config
1516
from .process import CalledProcessError, call, check_call, check_output
17+
from .utils import retry_on_exception
1618

1719
_logger = logging.getLogger(__name__)
1820

@@ -77,7 +79,11 @@ def temporary_clone(org, repo, branch):
7779
repo_url,
7880
"refs/heads/*:refs/heads/*",
7981
]
80-
check_call(fetch_cmd, cwd=repo_cache_dir)
82+
retry_on_exception(
83+
functools.partial(check_call, fetch_cmd, cwd=repo_cache_dir),
84+
"error: cannot lock ref",
85+
sleep_time=10.0,
86+
)
8187
# check if branch exist
8288
branches = check_output(["git", "branch"], cwd=repo_cache_dir)
8389
branches = [b.strip() for b in branches.split()]

src/oca_github_bot/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
# Copyright (c) ACSONE SA/NV 2021
22
# Distributed under the MIT License (http://opensource.org/licenses/MIT).
33

4+
import re
5+
import time
6+
47
from . import config
58

69

710
def hide_secrets(s: str) -> str:
811
# TODO do we want to hide other secrets ?
912
return s.replace(config.GITHUB_TOKEN, "***")
13+
14+
15+
def retry_on_exception(
16+
func, exception_regex: str, max_retries: int = 3, sleep_time: float = 5.0
17+
):
18+
"""Retry a function call if it raises an exception matching a regex."""
19+
counter = 0
20+
while True:
21+
try:
22+
return func()
23+
except Exception as e:
24+
if not re.search(exception_regex, str(e)):
25+
raise
26+
if counter >= max_retries:
27+
raise
28+
counter += 1
29+
time.sleep(sleep_time)

tests/test_utils.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (c) ACSONE SA/NV 2021
22
# Distributed under the MIT License (http://opensource.org/licenses/MIT).
33

4-
from oca_github_bot.utils import hide_secrets
4+
from oca_github_bot.utils import hide_secrets, retry_on_exception
55

66
from .common import set_config
77

@@ -16,3 +16,69 @@ def test_hide_secrets_github_token():
1616
assert "git push https://***@github.com" == hide_secrets(
1717
"git push https://[email protected]"
1818
)
19+
20+
21+
def test_retry_on_exception_raise_match():
22+
counter = 0
23+
24+
def func_that_raises():
25+
nonlocal counter
26+
counter += 1
27+
raise Exception("something")
28+
29+
max_retries = 2
30+
sleep_time = 0.1
31+
32+
try:
33+
retry_on_exception(
34+
func_that_raises,
35+
"something",
36+
max_retries=max_retries,
37+
sleep_time=sleep_time,
38+
)
39+
except Exception as e:
40+
assert "something" in str(e)
41+
assert counter == max_retries + 1
42+
43+
44+
def test_retry_on_exception_raise_no_match():
45+
counter = 0
46+
47+
def func_that_raises():
48+
nonlocal counter
49+
counter += 1
50+
raise Exception("somestuff")
51+
52+
max_retries = 2
53+
sleep_time = 0.1
54+
55+
try:
56+
retry_on_exception(
57+
func_that_raises,
58+
"something",
59+
max_retries=max_retries,
60+
sleep_time=sleep_time,
61+
)
62+
except Exception as e:
63+
assert "somestuff" in str(e)
64+
assert counter == 1
65+
66+
67+
def test_retry_on_exception_no_raise():
68+
counter = 0
69+
70+
def func_that_raises():
71+
nonlocal counter
72+
counter += 1
73+
return True
74+
75+
max_retries = 2
76+
sleep_time = 0.1
77+
78+
retry_on_exception(
79+
func_that_raises,
80+
"something",
81+
max_retries=max_retries,
82+
sleep_time=sleep_time,
83+
)
84+
assert counter == 1

tox.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ envlist =
44
py37
55
py38
66
py39
7+
py310
78
check_readme
89
pre_commit
910

@@ -13,6 +14,7 @@ python =
1314
3.7: py37
1415
3.8: py38
1516
3.9: py39
17+
3.10: py310
1618

1719
[testenv]
1820
skip_missing_interpreters = True

0 commit comments

Comments
 (0)