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:
|
||||
"""Строит Overpass QL запрос для всех POI типов в bbox ЕКБ."""
|
||||
def _build_overpass_query_single(key: str, value: str) -> str:
|
||||
"""Запрос для одной пары tag → нормированной категории.
|
||||
|
||||
Раньше делали один большой запрос на все 14 категорий — Overpass возвращал
|
||||
504 Gateway Timeout (запрос слишком тяжёлый). Сплит на per-category даёт
|
||||
14 быстрых запросов вместо одного 60+ секундного.
|
||||
"""
|
||||
south, west, north, east = EKB_BBOX
|
||||
bbox = f"({south},{west},{north},{east})"
|
||||
# out body даёт теги + meta для timestamp последней правки
|
||||
queries: list[str] = []
|
||||
for (k, v), _cat in OSM_CATEGORIES.items():
|
||||
queries.append(f'node["{k}"="{v}"]{bbox};')
|
||||
queries.append(f'way["{k}"="{v}"]{bbox};')
|
||||
inner = "\n".join(queries)
|
||||
return f"[out:json][timeout:60];(\n{inner}\n);out center meta;"
|
||||
return (
|
||||
f"[out:json][timeout:30];"
|
||||
f'(node["{key}"="{value}"]{bbox};way["{key}"="{value}"]{bbox};);'
|
||||
f"out center meta;"
|
||||
)
|
||||
|
||||
|
||||
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]:
|
||||
"""Запросить Overpass API, вернуть список raw OSM elements.
|
||||
"""Запросить Overpass API per category, вернуть combined список elements.
|
||||
|
||||
NB: Overpass блокирует default `python-httpx/*` User-Agent (отдаёт 406).
|
||||
Передаём явный UA с контактом проекта — это требование Overpass usage
|
||||
policy (https://operations.osmfoundation.org/policies/api/).
|
||||
Делаем 14 отдельных запросов вместо одного гигантского — большой запрос
|
||||
отдаёт 504 Gateway Timeout. Между запросами sleep 1с (Overpass usage
|
||||
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 = {
|
||||
"User-Agent": "GenDesign-SiteFinder/1.0 (+https://gendsgn.ru)",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
async with httpx.AsyncClient(timeout=120, headers=headers) as client:
|
||||
r = await client.post(OVERPASS_URL, data={"data": query})
|
||||
r.raise_for_status()
|
||||
elements: list[dict] = r.json().get("elements", [])
|
||||
logger.info("Overpass: получено %d элементов", len(elements))
|
||||
return elements
|
||||
all_elements: list[dict] = []
|
||||
async with httpx.AsyncClient(timeout=60, headers=headers) as client:
|
||||
for (key, value), category in OSM_CATEGORIES.items():
|
||||
query = _build_overpass_query_single(key, value)
|
||||
try:
|
||||
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]:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue