""" Evaluation API notification with retry logic Sends deployment metadata to evaluation endpoint """ import requests import time import logging logger = logging.getLogger(__name__) def notify_evaluation_api( evaluation_url: str, email: str, task: str, round: int, nonce: str, repo_url: str, commit_sha: str, pages_url: str, max_retries: int = 5 ) -> bool: """ Notify evaluation API with deployment details Implements exponential backoff retry logic Args: evaluation_url: Evaluation API endpoint email: Student email task: Task identifier round: Round number (1 or 2) nonce: Security nonce from request repo_url: GitHub repository URL commit_sha: Latest commit SHA pages_url: GitHub Pages URL max_retries: Maximum retry attempts Returns: True if notification successful, False otherwise """ payload = { "email": email, "task": task, "round": round, "nonce": nonce, "repo_url": repo_url, "commit_sha": commit_sha, "pages_url": pages_url } headers = { "Content-Type": "application/json" } # Exponential backoff: 1, 2, 4, 8, 16 seconds for attempt in range(max_retries): try: logger.info(f"Notifying evaluation API (attempt {attempt + 1}/{max_retries})...") logger.info(f"URL: {evaluation_url}") logger.info(f"Payload: {payload}") response = requests.post( evaluation_url, json=payload, headers=headers, timeout=30 ) if response.status_code == 200: logger.info(f"✓ Evaluation API returned HTTP 200") logger.info(f"Response: {response.text}") return True else: logger.warning(f"Evaluation API returned HTTP {response.status_code}") logger.warning(f"Response: {response.text}") # Don't retry on 4xx errors (client errors) if 400 <= response.status_code < 500: logger.error("Client error - not retrying") return False except requests.exceptions.Timeout: logger.warning(f"Request timeout on attempt {attempt + 1}") except requests.exceptions.ConnectionError as e: logger.warning(f"Connection error on attempt {attempt + 1}: {e}") except Exception as e: logger.error(f"Unexpected error on attempt {attempt + 1}: {e}") # Exponential backoff (except on last attempt) if attempt < max_retries - 1: wait_time = 2 ** attempt logger.info(f"Retrying in {wait_time} seconds...") time.sleep(wait_time) logger.error(f"✗ Failed to notify evaluation API after {max_retries} attempts") return False