OSM: Fair-Use-Rate-Limit + User-Agent für Overpass-Anfragen

Semaphore 2→1 (nur 1 gleichzeitige Anfrage), 2s Mindestabstand,
User-Agent mit App-Name und Kontakt — Standard-Höflichkeit für
Community-Dienste wie kumi.systems.
This commit is contained in:
rene 2026-04-25 22:09:50 +02:00
parent 92d583e661
commit 163b942ea4

View file

@ -24,8 +24,11 @@ OVERPASS_URLS = [
'https://overpass-api.de/api/interpreter',
]
# Globales Limit: max 2 gleichzeitige Overpass-Anfragen (Prewarm + User geteilt)
_overpass_sem = asyncio.Semaphore(2)
# Max 1 gleichzeitige Overpass-Anfrage + 2s Mindestabstand (Fair Use)
_overpass_sem = asyncio.Semaphore(1)
_overpass_last_req = 0.0
_OVERPASS_MIN_DELAY = 2.0 # Sekunden zwischen Anfragen
_OVERPASS_UA = 'BanYaro/1.0 (https://banyaro.app; dog-walking PWA; contact: mail@motocamp.de)'
OSM_QUERIES = {
'waste_basket': '[out:json][timeout:20];node["amenity"="waste_basket"]({bbox});out;',
@ -68,12 +71,22 @@ def _covering_tiles(south, west, north, east, zoom):
# Overpass-Fetch + Cache
# ------------------------------------------------------------------
async def _fetch_overpass(query):
global _overpass_last_req
for url in OVERPASS_URLS:
for attempt in range(2):
try:
async with _overpass_sem:
async with httpx.AsyncClient(timeout=40) as client:
# Fair-Use: Mindestabstand zwischen Anfragen einhalten
import time
wait = _OVERPASS_MIN_DELAY - (time.monotonic() - _overpass_last_req)
if wait > 0:
await asyncio.sleep(wait)
async with httpx.AsyncClient(
timeout=40,
headers={'User-Agent': _OVERPASS_UA},
) as client:
r = await client.post(url, data={'data': query})
_overpass_last_req = time.monotonic()
if r.status_code == 200:
return r.json().get('elements', [])
if r.status_code == 429: