fix(poi-sync): split Overpass query per category (504 Gateway Timeout)
This commit is contained in:
parent
93f13795bb
commit
3aeda297ee
1 changed files with 37 additions and 21 deletions
|
|
@ -42,17 +42,20 @@ OSM_CATEGORIES: dict[tuple[str, str], str] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _build_overpass_query() -> str:
|
def _build_overpass_query_single(key: str, value: str) -> str:
|
||||||
"""Строит Overpass QL запрос для всех POI типов в bbox ЕКБ."""
|
"""Запрос для одной пары tag → нормированной категории.
|
||||||
|
|
||||||
|
Раньше делали один большой запрос на все 14 категорий — Overpass возвращал
|
||||||
|
504 Gateway Timeout (запрос слишком тяжёлый). Сплит на per-category даёт
|
||||||
|
14 быстрых запросов вместо одного 60+ секундного.
|
||||||
|
"""
|
||||||
south, west, north, east = EKB_BBOX
|
south, west, north, east = EKB_BBOX
|
||||||
bbox = f"({south},{west},{north},{east})"
|
bbox = f"({south},{west},{north},{east})"
|
||||||
# out body даёт теги + meta для timestamp последней правки
|
return (
|
||||||
queries: list[str] = []
|
f"[out:json][timeout:30];"
|
||||||
for (k, v), _cat in OSM_CATEGORIES.items():
|
f'(node["{key}"="{value}"]{bbox};way["{key}"="{value}"]{bbox};);'
|
||||||
queries.append(f'node["{k}"="{v}"]{bbox};')
|
f"out center meta;"
|
||||||
queries.append(f'way["{k}"="{v}"]{bbox};')
|
)
|
||||||
inner = "\n".join(queries)
|
|
||||||
return f"[out:json][timeout:60];(\n{inner}\n);out center meta;"
|
|
||||||
|
|
||||||
|
|
||||||
def _classify(tags: dict[str, str]) -> str | None:
|
def _classify(tags: dict[str, str]) -> str | None:
|
||||||
|
|
@ -64,24 +67,37 @@ def _classify(tags: dict[str, str]) -> str | None:
|
||||||
|
|
||||||
|
|
||||||
async def fetch_overpass() -> list[dict]:
|
async def fetch_overpass() -> list[dict]:
|
||||||
"""Запросить Overpass API, вернуть список raw OSM elements.
|
"""Запросить Overpass API per category, вернуть combined список elements.
|
||||||
|
|
||||||
NB: Overpass блокирует default `python-httpx/*` User-Agent (отдаёт 406).
|
Делаем 14 отдельных запросов вместо одного гигантского — большой запрос
|
||||||
Передаём явный UA с контактом проекта — это требование Overpass usage
|
отдаёт 504 Gateway Timeout. Между запросами sleep 1с (Overpass usage
|
||||||
policy (https://operations.osmfoundation.org/policies/api/).
|
policy: max 2 concurrent, лучше 1 req/s).
|
||||||
|
|
||||||
|
Overpass блокирует default `python-httpx/*` User-Agent (406) — поэтому
|
||||||
|
явный UA с контактом проекта.
|
||||||
"""
|
"""
|
||||||
query = _build_overpass_query()
|
|
||||||
logger.info("Overpass: отправляем запрос (%d символов)", len(query))
|
|
||||||
headers = {
|
headers = {
|
||||||
"User-Agent": "GenDesign-SiteFinder/1.0 (+https://gendsgn.ru)",
|
"User-Agent": "GenDesign-SiteFinder/1.0 (+https://gendsgn.ru)",
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
}
|
}
|
||||||
async with httpx.AsyncClient(timeout=120, headers=headers) as client:
|
all_elements: list[dict] = []
|
||||||
r = await client.post(OVERPASS_URL, data={"data": query})
|
async with httpx.AsyncClient(timeout=60, headers=headers) as client:
|
||||||
r.raise_for_status()
|
for (key, value), category in OSM_CATEGORIES.items():
|
||||||
elements: list[dict] = r.json().get("elements", [])
|
query = _build_overpass_query_single(key, value)
|
||||||
logger.info("Overpass: получено %d элементов", len(elements))
|
try:
|
||||||
return elements
|
r = await client.post(OVERPASS_URL, data={"data": query})
|
||||||
|
r.raise_for_status()
|
||||||
|
elements: list[dict] = r.json().get("elements", [])
|
||||||
|
logger.info("Overpass: %s=%s (%s) → %d", key, value, category, len(elements))
|
||||||
|
all_elements.extend(elements)
|
||||||
|
except Exception as e:
|
||||||
|
# Не падаем на одной категории — логируем и продолжаем
|
||||||
|
logger.warning("Overpass failed for %s=%s: %s", key, value, e)
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
logger.info(
|
||||||
|
"Overpass: total %d elements across %d categories", len(all_elements), len(OSM_CATEGORIES)
|
||||||
|
)
|
||||||
|
return all_elements
|
||||||
|
|
||||||
|
|
||||||
def sync_poi_to_db() -> dict[str, int]:
|
def sync_poi_to_db() -> dict[str, int]:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue