fix(tradein/geocoder): темп Nominatim сдерживается перед запросом, а не после успеха (#2953) #2954

Merged
bot-backend merged 1 commit from fix/2953-nominatim-throttle into main 2026-08-20 07:55:42 +00:00

1 commit

Author SHA1 Message Date
5222f477db fix(tradein/geocoder): темп Nominatim сдерживается перед запросом, а не после успеха (#2953)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m44s
На проде — 194 события «429 Too many requests» от Nominatim за неделю. Это не
внешняя случайность: политику 1 req/sec изображали три разрозненных
asyncio.sleep(1.0), и ни один не давал ограничения на самом деле.

  geocode()           — сон ВНУТРИ `if result is not None`, то есть только
                        после УСПЕХА; после неудачи паузы не было;
  _nominatim_lookup() — сон МЕЖДУ typo-вариантами, но не перед tier-1;
  цикл бэкфилла       — своей паузы не имеет вовсе, зовёт geocode()
                        последовательно.

Для неразрешимого адреса выходило 5 запросов за 4 секунды и сразу следующий
адрес без паузы. То есть темп сбрасывался ровно тогда, когда сервер и просит
притормозить, и разгонялся ровно на тех адресах, что не резолвятся.

А череда неудач — не редкость, а норма прогона. Разбор 16947 объявлений без
координат на 20.08: активных 1948, из них с пригодным адресом 1471, доступно
бэкфиллу прямо сейчас 47, а 1424 лежат в семидневном backoff — то есть 97%
активных «без координат» это повторные неудачи, возвращающиеся в очередь
каждые 7 суток. Разгон происходит каждый прогон.

Теперь пауза берётся ПЕРЕД каждым обращением и одна на все три точки вызова
(/search x2, /reverse). Четыре прежних sleep убраны как избыточные.

Повторы на 429 намеренно НЕ трогал. Если убрать их той же правкой, падение
счётчика 429 нельзя будет приписать именно ограничителю темпа — а критерий
приёмки в #2953 сформулирован через этот счётчик.

Тест проверяет ПОВЕДЕНИЕ (расстояние между исходящими запросами), а не наличие
нового символа: импорт _nominatim_throttle дал бы на origin/main ImportError,
то есть «возможности нет», и красный ничего бы не доказывал. Против кода
origin/main:

  зазоры между тремя запросами   [0.0003, 0.0001] вместо >=0.08  -> падает
  стык двух неудачных поисков    0.0022с          вместо >=0.08  -> падает
  первый запрос не ждёт впустую  контроль, зелёный на обеих сторонах

Прогон tradein-сьюта: 280 failed / 2099 passed против базы 280 failed /
2096 passed на origin/main — ни одного нового падения, +3 своих. Падения и
216 collection-errors средовые (нет scraper_kit/bcrypt/lxml в локальном venv).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 12:46:41 +05:00