diff --git a/src/data_overpass.py b/src/data_overpass.py index 54da278..af790c6 100644 --- a/src/data_overpass.py +++ b/src/data_overpass.py @@ -1,6 +1,7 @@ """Overpass Turbo: OverpassQL-Queries gegen OpenStreetMap ausfuehren.""" import logging import time +import asyncio import hashlib import httpx from fastapi import APIRouter, HTTPException @@ -19,10 +20,13 @@ _CACHE_TTL = 300 # 5 Minuten _MAX_CACHE_ENTRIES = 50 # --- Overpass API --- -_OVERPASS_URL = "https://overpass-api.de/api/interpreter" -_OVERPASS_FALLBACK = "https://overpass.kumi.systems/api/interpreter" +_OVERPASS_URLS = [ + "https://overpass-api.de/api/interpreter", + "https://z.overpass-api.de/api/interpreter", +] _MAX_ELEMENTS = 5000 _TIMEOUT = 60 +_RETRY_CODES = {502, 504, 429} # Transiente Fehler class OverpassRequest(BaseModel): @@ -370,20 +374,30 @@ async def execute_query(req: OverpassRequest): _last_request_time = time.time() - # Query ausfuehren + # Query ausfuehren (mit Retry bei transienten Fehlern) data = None - for url in [_OVERPASS_URL, _OVERPASS_FALLBACK]: - try: - async with httpx.AsyncClient(timeout=_TIMEOUT) as client: - r = await client.post(url, data={"data": query}) - r.raise_for_status() - data = r.json() + last_error = None + for url in _OVERPASS_URLS: + for attempt in range(2): + try: + async with httpx.AsyncClient(timeout=_TIMEOUT) as client: + r = await client.post(url, data={"data": query}) + if r.status_code in _RETRY_CODES and attempt == 0: + logger.info(f"Overpass {url}: {r.status_code}, retry in 2s...") + await asyncio.sleep(2) + continue + r.raise_for_status() + data = r.json() + break + except Exception as e: + last_error = f"{url}: {e}" + logger.warning(f"Overpass {url} (attempt {attempt+1}): {e}") break - except Exception as e: - logger.warning(f"Overpass {url}: {e}") - continue + if data is not None: + break if data is None: + logger.error(f"Alle Overpass-Endpunkte fehlgeschlagen: {last_error}") raise HTTPException(502, "Overpass API nicht erreichbar") elements = data.get("elements", [])