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:
michaelmartinez
2025-12-22 14:23:02 -08:00
parent 81a72ac8af
commit 89502c326d
3 changed files with 19 additions and 5 deletions

View File

@@ -4,6 +4,7 @@
import logging
import os
import sys
from github_backup import max_retries
from github_backup.github_backup import (
backup_account,
@@ -39,6 +40,7 @@ logging.basicConfig(level=logging.INFO, handlers=[stdout_handler, stderr_handler
def main():
"""Main entry point for github-backup CLI."""
args = parse_args()
max_retries.MAX_RETRIES = args.max_retries
if args.private and not get_auth(args):
logger.warning(

View File

@@ -25,6 +25,7 @@ from http.client import IncompleteRead
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode, urlparse
from urllib.request import HTTPRedirectHandler, Request, build_opener, urlopen
from github_backup import max_retries
try:
from . import __version__
@@ -75,7 +76,7 @@ else:
)
# Retry configuration
MAX_RETRIES = 5
MAX_RETRIES = max_retries.MAX_RETRIES
def logging_subprocess(
@@ -468,6 +469,13 @@ def parse_args(args=None):
parser.add_argument(
"--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)
@@ -737,16 +745,19 @@ def make_request_with_retry(request, auth):
except HTTPError as exc:
# HTTPError can be used as a response-like object
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
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 for {request.full_url}")
raise
delay = calculate_retry_delay(attempt, exc.headers)
logger.warning(
f"HTTP {exc.code}, retrying in {delay:.1f}s "
f"(attempt {attempt + 1}/{MAX_RETRIES})"
f"HTTP {exc.code} ({exc.reason}), retrying in {delay:.1f}s "
f"(attempt {attempt + 1}/{MAX_RETRIES}) for {request.full_url}"
)
if auth is None and exc.code in (403, 429):
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:
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
delay = calculate_retry_delay(attempt, {})
logger.warning(
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)

View File

@@ -0,0 +1 @@
MAX_RETRIES=None