mirror of
https://github.com/josegonzalez/python-github-backup.git
synced 2025-12-25 17:11:11 +01:00
update retry logic and logging
### What 1. configureable retry count 2. additional logging ### Why 1. pass retry count as a command line arg; default 5 2. show details when api requests fail ### Testing before merge compiles cleanly ### Validation after merge compile and test ### Issue addressed by this PR https://github.com/stellar/ops/issues/2039
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from github_backup import max_retries
|
||||||
|
|
||||||
from github_backup.github_backup import (
|
from github_backup.github_backup import (
|
||||||
backup_account,
|
backup_account,
|
||||||
@@ -39,6 +40,7 @@ logging.basicConfig(level=logging.INFO, handlers=[stdout_handler, stderr_handler
|
|||||||
def main():
|
def main():
|
||||||
"""Main entry point for github-backup CLI."""
|
"""Main entry point for github-backup CLI."""
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
max_retries.MAX_RETRIES = args.max_retries
|
||||||
|
|
||||||
if args.private and not get_auth(args):
|
if args.private and not get_auth(args):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from http.client import IncompleteRead
|
|||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
from urllib.parse import urlencode, urlparse
|
from urllib.parse import urlencode, urlparse
|
||||||
from urllib.request import HTTPRedirectHandler, Request, build_opener, urlopen
|
from urllib.request import HTTPRedirectHandler, Request, build_opener, urlopen
|
||||||
|
from github_backup import max_retries
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from . import __version__
|
from . import __version__
|
||||||
@@ -75,7 +76,7 @@ else:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Retry configuration
|
# Retry configuration
|
||||||
MAX_RETRIES = 5
|
MAX_RETRIES = max_retries.MAX_RETRIES
|
||||||
|
|
||||||
|
|
||||||
def logging_subprocess(
|
def logging_subprocess(
|
||||||
@@ -468,6 +469,13 @@ def parse_args(args=None):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--exclude", dest="exclude", help="names of repositories to exclude", nargs="*"
|
"--exclude", dest="exclude", help="names of repositories to exclude", nargs="*"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--retries",
|
||||||
|
dest="max_retries",
|
||||||
|
type=int,
|
||||||
|
default=5,
|
||||||
|
help="maximum number of retries for API calls (default: 5)",
|
||||||
|
)
|
||||||
return parser.parse_args(args)
|
return parser.parse_args(args)
|
||||||
|
|
||||||
|
|
||||||
@@ -737,16 +745,19 @@ def make_request_with_retry(request, auth):
|
|||||||
except HTTPError as exc:
|
except HTTPError as exc:
|
||||||
# HTTPError can be used as a response-like object
|
# HTTPError can be used as a response-like object
|
||||||
if not is_retryable_status(exc.code, exc.headers):
|
if not is_retryable_status(exc.code, exc.headers):
|
||||||
|
logger.error(f"API Error: {exc.code} {exc.reason} for {request.full_url}")
|
||||||
raise # Non-retryable error
|
raise # Non-retryable error
|
||||||
|
|
||||||
if attempt >= MAX_RETRIES - 1:
|
if attempt >= MAX_RETRIES - 1:
|
||||||
logger.error(f"HTTP {exc.code} failed after {MAX_RETRIES} attempts")
|
logger.error(f"HTTP {exc.code} failed after {MAX_RETRIES} attempts")
|
||||||
|
logger.error(f"HTTP {exc.code} failed after {MAX_RETRIES} attempts for {request.full_url}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
delay = calculate_retry_delay(attempt, exc.headers)
|
delay = calculate_retry_delay(attempt, exc.headers)
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"HTTP {exc.code}, retrying in {delay:.1f}s "
|
f"HTTP {exc.code} ({exc.reason}), retrying in {delay:.1f}s "
|
||||||
f"(attempt {attempt + 1}/{MAX_RETRIES})"
|
f"(attempt {attempt + 1}/{MAX_RETRIES}) for {request.full_url}"
|
||||||
|
|
||||||
)
|
)
|
||||||
if auth is None and exc.code in (403, 429):
|
if auth is None and exc.code in (403, 429):
|
||||||
logger.info("Hint: Authenticate to raise your GitHub rate limit")
|
logger.info("Hint: Authenticate to raise your GitHub rate limit")
|
||||||
@@ -754,12 +765,12 @@ def make_request_with_retry(request, auth):
|
|||||||
|
|
||||||
except (URLError, socket.error) as e:
|
except (URLError, socket.error) as e:
|
||||||
if attempt >= MAX_RETRIES - 1:
|
if attempt >= MAX_RETRIES - 1:
|
||||||
logger.error(f"Connection error failed after {MAX_RETRIES} attempts: {e}")
|
logger.error(f"Connection error failed after {MAX_RETRIES} attempts: {e} for {request.full_url}")
|
||||||
raise
|
raise
|
||||||
delay = calculate_retry_delay(attempt, {})
|
delay = calculate_retry_delay(attempt, {})
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Connection error: {e}, retrying in {delay:.1f}s "
|
f"Connection error: {e}, retrying in {delay:.1f}s "
|
||||||
f"(attempt {attempt + 1}/{MAX_RETRIES})"
|
f"(attempt {attempt + 1}/{MAX_RETRIES}) for {request.full_url}"
|
||||||
)
|
)
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
|
|
||||||
|
|||||||
1
github_backup/max_retries.py
Normal file
1
github_backup/max_retries.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MAX_RETRIES=None
|
||||||
Reference in New Issue
Block a user