fix(tradein): бюджет по времени в geocode-missing — cron не таймаутит

cron geocode-missing-шаг дёргает эндпоинт через `curl -m 320`, а
геокодинг 100 адресов упирается в Nominatim (1 req/sec + typo-тиры на
провалах) и выходит за 320с. При таймауте curl cron-loop обрывался —
объявления Cian/N1 оставались без координат и были невидимы для оценки
(ST_DWithin по geom). Сейчас ~200 таких объявлений в БД.

geocode_missing теперь выходит из цикла по бюджету 240с (заведомо
меньше cron-таймаута) и возвращает remaining > 0 — cron штатно
продолжает следующим чанком. Заодно убран мёртвый import asyncio.
This commit is contained in:
Light1YT 2026-05-22 14:37:15 +05:00
parent 389fcb2146
commit 0b14538f7d

View file

@ -5,8 +5,8 @@
from __future__ import annotations from __future__ import annotations
import asyncio
import logging import logging
import time
from typing import Annotated, Literal from typing import Annotated, Literal
from fastapi import APIRouter, Depends, Header, HTTPException from fastapi import APIRouter, Depends, Header, HTTPException
@ -145,8 +145,9 @@ async def geocode_missing(
"""Геокодинг listings ИЛИ deals у которых нет lat/lon (используя address). """Геокодинг listings ИЛИ deals у которых нет lat/lon (используя address).
target=listings (по умолч.) объявления Cian/N1; target=deals сделки Росреестра. target=listings (по умолч.) объявления Cian/N1; target=deals сделки Росреестра.
Чанк-обработка: limit=100 ~150-200с (Nominatim 1 req/sec). cron вызывает Чанк-обработка с бюджетом по времени (~240с, заведомо меньше cron
в цикле пока `remaining` > 0. `curl -m 320`): за вызов геокодим сколько успеваем, остаток уходит в
`remaining`, cron вызывает в цикле пока `remaining` > 0.
geocode_tried_at: после КАЖДОЙ попытки (успех/провал) ставим NOW(). Failed- geocode_tried_at: после КАЖДОЙ попытки (успех/провал) ставим NOW(). Failed-
адреса не выбираются повторно 7 дней cron-loop завершается, не зацикливается. адреса не выбираются повторно 7 дней cron-loop завершается, не зацикливается.
@ -175,9 +176,21 @@ async def geocode_missing(
{"limit": limit}, {"limit": limit},
).mappings().all() ).mappings().all()
# Бюджет по времени: геокодинг упирается в Nominatim (1 req/sec + typo-тиры
# на провалах), 100 адресов могут не уложиться в cron-таймаут `curl -m 320`.
# Выходим из цикла заведомо раньше — remaining > 0 заставит cron продолжить.
budget_sec = 240.0
started = time.monotonic()
geocoded = 0 geocoded = 0
skipped = 0 skipped = 0
for row in rows: for row in rows:
if time.monotonic() - started > budget_sec:
logger.info(
"geocode-missing: бюджет %.0fс исчерпан, обработано %d — cron продолжит",
budget_sec, geocoded + skipped,
)
break
clean = _clean_address_for_geocode(row["address"]) clean = _clean_address_for_geocode(row["address"])
result = await geocode(clean, db) result = await geocode(clean, db)
if result is None: if result is None: