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

Merged
lekss361 merged 1 commit from fix/tradein-geocode-time-budget into main 2026-05-22 09:37:42 +00:00

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: