From 006407ca1d4ce207e2319f804a65f81e95d68f32 Mon Sep 17 00:00:00 2001 From: Yves Gugger Date: Wed, 17 Dec 2025 08:02:59 +0100 Subject: [PATCH] Add retry logic (3 attempts with backoff) to CZDS zone downloads Large zone files (100-200MB) were failing due to connection interruptions. Now retries up to 3 times with 30s/60s/90s backoff between attempts. --- backend/scripts/sync_all_zones.py | 117 ++++++++++++++++-------------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/backend/scripts/sync_all_zones.py b/backend/scripts/sync_all_zones.py index 0d7c2f6..f408219 100644 --- a/backend/scripts/sync_all_zones.py +++ b/backend/scripts/sync_all_zones.py @@ -92,60 +92,71 @@ async def get_db_session(): return async_session() -def download_czds_zone(tld: str) -> Optional[Path]: - """Download a single CZDS zone file using pyCZDS""" - try: - from pyczds.client import CZDSClient - - # Read credentials from .env - env_file = Path(__file__).parent.parent / ".env" - if not env_file.exists(): - env_file = Path("/home/user/pounce/backend/.env") - - env_content = env_file.read_text() - username = password = None - - for line in env_content.splitlines(): - if line.startswith("CZDS_USERNAME="): - username = line.split("=", 1)[1].strip() - elif line.startswith("CZDS_PASSWORD="): - password = line.split("=", 1)[1].strip() - - if not username or not password: - logger.error(f"CZDS credentials not found in .env") - return None - - client = CZDSClient(username, password) - urls = client.get_zonefiles_list() - - # Find URL for this TLD - target_url = None - for url in urls: - if f"{tld}.zone" in url or f"/{tld}." in url: - target_url = url - break - - if not target_url: - logger.warning(f"No access to .{tld} zone file") - return None - - logger.info(f"Downloading .{tld} from CZDS...") - result = client.get_zonefile(target_url, download_dir=str(CZDS_DIR)) - - # Find the downloaded file - gz_file = CZDS_DIR / f"{tld}.txt.gz" - if gz_file.exists(): - return gz_file - - # Try alternative naming - for f in CZDS_DIR.glob(f"*{tld}*.gz"): - return f +def download_czds_zone(tld: str, max_retries: int = 3) -> Optional[Path]: + """Download a single CZDS zone file using pyCZDS with retry logic""" + import time + + for attempt in range(max_retries): + try: + from pyczds.client import CZDSClient - return None - - except Exception as e: - logger.error(f"CZDS download failed for .{tld}: {e}") - return None + # Read credentials from .env + env_file = Path(__file__).parent.parent / ".env" + if not env_file.exists(): + env_file = Path("/home/user/pounce/backend/.env") + + env_content = env_file.read_text() + username = password = None + + for line in env_content.splitlines(): + if line.startswith("CZDS_USERNAME="): + username = line.split("=", 1)[1].strip() + elif line.startswith("CZDS_PASSWORD="): + password = line.split("=", 1)[1].strip() + + if not username or not password: + logger.error(f"CZDS credentials not found in .env") + return None + + client = CZDSClient(username, password) + urls = client.get_zonefiles_list() + + # Find URL for this TLD + target_url = None + for url in urls: + if f"{tld}.zone" in url or f"/{tld}." in url: + target_url = url + break + + if not target_url: + logger.warning(f"No access to .{tld} zone file") + return None + + logger.info(f"Downloading .{tld} from CZDS... (attempt {attempt + 1}/{max_retries})") + result = client.get_zonefile(target_url, download_dir=str(CZDS_DIR)) + + # Find the downloaded file + gz_file = CZDS_DIR / f"{tld}.txt.gz" + if gz_file.exists(): + return gz_file + + # Try alternative naming + for f in CZDS_DIR.glob(f"*{tld}*.gz"): + return f + + return None + + except Exception as e: + logger.warning(f"CZDS download attempt {attempt + 1} failed for .{tld}: {e}") + if attempt < max_retries - 1: + wait_time = (attempt + 1) * 30 # 30s, 60s, 90s backoff + logger.info(f"Retrying in {wait_time}s...") + time.sleep(wait_time) + else: + logger.error(f"CZDS download failed for .{tld} after {max_retries} attempts") + return None + + return None def download_switch_zone(tld: str) -> Optional[Path]: