Spaces:
Sleeping
Sleeping
File size: 2,716 Bytes
65602c7 e549219 65602c7 e549219 65602c7 e549219 65602c7 e549219 65602c7 e549219 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | """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
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=1, max=60),
reraise=True
)
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()
|