Spaces:
Sleeping
Sleeping
Download app/services/notify.py from adrija93/TDS-Project1-API: direct link, hf CLI and curl.
- Browser
- Download file 2.72 kB
-
https://huggingface.co/spaces/adrija93/TDS-Project1-API/resolve/main/app/services/notify.py
- Command line
-
hf download hf://spaces/adrija93/TDS-Project1-API/app/services/notify.py
-
curl -L -o notify.py https://huggingface.co/spaces/adrija93/TDS-Project1-API/resolve/main/app/services/notify.py
2.72 kB
| """Service to handle task result notifications with retries and diagnostics.""" | |
| from typing import Dict, Any | |
| import httpx | |
| from pydantic import HttpUrl | |
| from tenacity import retry, stop_after_attempt, wait_exponential | |
| class NotificationService: | |
| """Service for sending notifications with retry logic.""" | |
| def __init__(self, max_retries: int = 5, timeout: float = 30.0): | |
| """Create a reusable HTTP client. | |
| timeout can be a float or seconds; we prefer a more generous read timeout on Spaces. | |
| """ | |
| # Increase timeouts to accommodate slower evaluators | |
| timeout_cfg = httpx.Timeout( | |
| connect=10.0, | |
| read=max(60.0, float(timeout)), | |
| write=30.0, | |
| pool=10.0, | |
| ) | |
| # Follow redirects to ensure we validate the final response code | |
| self.client = httpx.AsyncClient(timeout=timeout_cfg, follow_redirects=True, headers={ | |
| "User-Agent": "TDS-Project1-API/1.0" | |
| }) | |
| self.max_retries = max_retries | |
| async def notify_evaluation(self, url: str | HttpUrl, task_result: Dict[str, Any]) -> None: | |
| """ | |
| Send task result to evaluation URL with retries. | |
| Args: | |
| url: The evaluation URL to send results to (str or HttpUrl) | |
| task_result: The task result data to send | |
| Raises: | |
| httpx.HTTPError: If the request fails after all retries | |
| """ | |
| # Convert HttpUrl to string if needed | |
| url_str = str(url) if not isinstance(url, str) else url | |
| try: | |
| response = await self.client.post( | |
| url_str, | |
| json=task_result, | |
| headers={"Content-Type": "application/json"} | |
| ) | |
| except httpx.RequestError as e: | |
| # Provide clearer diagnostics for network-level errors | |
| print(f"[Notify] Request error to {url_str}: {e}") | |
| raise | |
| # Enforce strict 200 OK per requirement (not just any 2xx) | |
| if response.status_code != 200: | |
| body_preview = (response.text or "").strip() | |
| if len(body_preview) > 512: | |
| body_preview = body_preview[:512] + "..." | |
| print(f"[Notify] Non-200 from evaluator: {response.status_code}. Body: {body_preview}") | |
| raise httpx.HTTPStatusError( | |
| f"Expected 200 OK, got {response.status_code}", request=response.request, response=response | |
| ) | |
| async def close(self): | |
| """Close the HTTP client.""" | |
| await self.client.aclose() | |