fix: toten Overpass-Fallback ersetzen + Retry bei 504
- kumi.systems Fallback (tot) durch z.overpass-api.de ersetzt - Retry-Logik bei transienten HTTP-Fehlern (502/504/429) - 2s Pause vor Retry, dann naechster Endpunkt
Dieser Commit ist enthalten in:
@@ -1,6 +1,7 @@
|
|||||||
"""Overpass Turbo: OverpassQL-Queries gegen OpenStreetMap ausfuehren."""
|
"""Overpass Turbo: OverpassQL-Queries gegen OpenStreetMap ausfuehren."""
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import httpx
|
import httpx
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
@@ -19,10 +20,13 @@ _CACHE_TTL = 300 # 5 Minuten
|
|||||||
_MAX_CACHE_ENTRIES = 50
|
_MAX_CACHE_ENTRIES = 50
|
||||||
|
|
||||||
# --- Overpass API ---
|
# --- Overpass API ---
|
||||||
_OVERPASS_URL = "https://overpass-api.de/api/interpreter"
|
_OVERPASS_URLS = [
|
||||||
_OVERPASS_FALLBACK = "https://overpass.kumi.systems/api/interpreter"
|
"https://overpass-api.de/api/interpreter",
|
||||||
|
"https://z.overpass-api.de/api/interpreter",
|
||||||
|
]
|
||||||
_MAX_ELEMENTS = 5000
|
_MAX_ELEMENTS = 5000
|
||||||
_TIMEOUT = 60
|
_TIMEOUT = 60
|
||||||
|
_RETRY_CODES = {502, 504, 429} # Transiente Fehler
|
||||||
|
|
||||||
|
|
||||||
class OverpassRequest(BaseModel):
|
class OverpassRequest(BaseModel):
|
||||||
@@ -370,20 +374,30 @@ async def execute_query(req: OverpassRequest):
|
|||||||
|
|
||||||
_last_request_time = time.time()
|
_last_request_time = time.time()
|
||||||
|
|
||||||
# Query ausfuehren
|
# Query ausfuehren (mit Retry bei transienten Fehlern)
|
||||||
data = None
|
data = None
|
||||||
for url in [_OVERPASS_URL, _OVERPASS_FALLBACK]:
|
last_error = None
|
||||||
try:
|
for url in _OVERPASS_URLS:
|
||||||
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
for attempt in range(2):
|
||||||
r = await client.post(url, data={"data": query})
|
try:
|
||||||
r.raise_for_status()
|
async with httpx.AsyncClient(timeout=_TIMEOUT) as client:
|
||||||
data = r.json()
|
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
|
break
|
||||||
except Exception as e:
|
if data is not None:
|
||||||
logger.warning(f"Overpass {url}: {e}")
|
break
|
||||||
continue
|
|
||||||
|
|
||||||
if data is None:
|
if data is None:
|
||||||
|
logger.error(f"Alle Overpass-Endpunkte fehlgeschlagen: {last_error}")
|
||||||
raise HTTPException(502, "Overpass API nicht erreichbar")
|
raise HTTPException(502, "Overpass API nicht erreichbar")
|
||||||
|
|
||||||
elements = data.get("elements", [])
|
elements = data.get("elements", [])
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren