feat(scrapers): live pacing-регулятор + data-quality coverage API #1829

Merged
lekss361 merged 1 commit from feat/scrapers-config-apis into main 2026-06-20 12:31:48 +00:00
Owner

Бэкенд для двух дыр из аудита /scrapers (наблюдаемость данных + тюнинг без recreate). Парный фронт — отдельный PR.

A. Live pacing-регулятор (per-provider интервалы без recreate)

До этого per-provider BROWSER_MIN_PAGE_INTERVAL_S_* менялись только через env + recreate контейнера. Теперь — live in-memory.

  • tradein-mvp/browser/server.py: GET /pacing (текущие живые интервалы + env-дефолт к чему сбросится на рестарте) и PUT /pacing {source, interval_s} (валидация source∈{avito,cian,yandex,generic}, interval_s≥0; пишет _MIN_PAGE_INTERVAL_BY_PROVIDER in-memory).
  • admin.py: GET /api/v1/admin/scraper/pacing{providers:[{source, interval_s, env_default_s}]} и PUT /scraper/pacing/{source} body {interval_s} (Field ge=0 le=120) → {ok, source, interval_s}. Прокси к browser (паттерн _probe_browser_health); browser недоступен → 502/503 с понятным detail.
  • In-memory by design: сбрасывается на env-дефолт при рестарте browser (env = durable default).

B. Data-quality coverage

  • admin.py: GET /api/v1/admin/scraper/data-quality → fill% detail-полей по source + houses-enrichment.
    {sources:[{source, active_count, fields:{<field>: pct}}],
     houses:{total, validated_pct, rating_pct, house_type_pct, reviews_count}}
    
    Один проход COUNT(*) FILTER по listings WHERE is_active GROUP BY source. Поля (подтверждены через схему): description, photo_urls (jsonb <>'[]'), address, lat, lon, kitchen_area_m2, living_area_m2, ceiling_height (cian), ceiling_height_m (avito), metro_stations (jsonb). Houses: validated (avito_validated_at), rating_score, house_type, house_reviews count.

Тесты

browser pytest 16 passed (pacing GET/PUT + валидация), backend pytest 21 passed (pacing-прокси с мок-httpx + data-quality shape/диапазоны). ruff clean.

Деплой

browser + backend Python-изменения → пересборка обоих образов + recreate tradein-browser и tradein-backend. Эндпоинты новые (аддитивно), без миграций. ⚠️ Мержить и дать деплою доехать ДО фронт-PR (иначе фронт-секции pacing/coverage покажут «API недоступен» — graceful, но пусто). NB: не мержить вплотную к другим tradein-PR (rapid-merge → cancelled test-gate → stale image).

Cross-ref аудит /scrapers, PR #1826 (per-provider pacing env).

Бэкенд для двух дыр из аудита `/scrapers` (наблюдаемость данных + тюнинг без recreate). Парный фронт — отдельный PR. ## A. Live pacing-регулятор (per-provider интервалы без recreate) До этого per-provider `BROWSER_MIN_PAGE_INTERVAL_S_*` менялись только через env + recreate контейнера. Теперь — live in-memory. - **`tradein-mvp/browser/server.py`**: `GET /pacing` (текущие живые интервалы + env-дефолт к чему сбросится на рестарте) и `PUT /pacing {source, interval_s}` (валидация source∈{avito,cian,yandex,generic}, interval_s≥0; пишет `_MIN_PAGE_INTERVAL_BY_PROVIDER` in-memory). - **`admin.py`**: `GET /api/v1/admin/scraper/pacing` → `{providers:[{source, interval_s, env_default_s}]}` и `PUT /scraper/pacing/{source}` body `{interval_s}` (Field ge=0 le=120) → `{ok, source, interval_s}`. Прокси к browser (паттерн `_probe_browser_health`); browser недоступен → 502/503 с понятным detail. - In-memory by design: сбрасывается на env-дефолт при рестарте browser (env = durable default). ## B. Data-quality coverage - **`admin.py`**: `GET /api/v1/admin/scraper/data-quality` → fill% detail-полей по source + houses-enrichment. ``` {sources:[{source, active_count, fields:{<field>: pct}}], houses:{total, validated_pct, rating_pct, house_type_pct, reviews_count}} ``` Один проход `COUNT(*) FILTER` по `listings WHERE is_active GROUP BY source`. Поля (подтверждены через схему): description, photo_urls (jsonb `<>'[]'`), address, lat, lon, kitchen_area_m2, living_area_m2, ceiling_height (cian), ceiling_height_m (avito), metro_stations (jsonb). Houses: validated (`avito_validated_at`), rating_score, house_type, `house_reviews` count. ## Тесты browser pytest 16 passed (pacing GET/PUT + валидация), backend pytest 21 passed (pacing-прокси с мок-httpx + data-quality shape/диапазоны). ruff clean. ## Деплой browser + backend Python-изменения → пересборка обоих образов + recreate `tradein-browser` и `tradein-backend`. Эндпоинты новые (аддитивно), без миграций. ⚠️ Мержить и дать деплою доехать ДО фронт-PR (иначе фронт-секции pacing/coverage покажут «API недоступен» — graceful, но пусто). NB: не мержить вплотную к другим tradein-PR (rapid-merge → cancelled test-gate → stale image). Cross-ref аудит `/scrapers`, PR #1826 (per-provider pacing env).
lekss361 added 1 commit 2026-06-20 09:51:33 +00:00
feat(scrapers): live pacing-регулятор (GET/PUT /scraper/pacing) + data-quality coverage endpoint
All checks were successful
CI / changes (pull_request) Successful in 7s
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
b6634ea40c
- browser/server.py: GET /pacing и PUT /pacing — read/write _MIN_PAGE_INTERVAL_BY_PROVIDER
  in-memory; валидация source in PROVIDERS, interval_s >= 0; логирует изменения; сбрасывается
  к env-дефолту на рестарте by design
- backend/admin.py: GET /scraper/pacing — прокси к browser /pacing, PacingResponse pydantic;
  PUT /scraper/pacing/{source} — прокси PUT с валидацией ge=0 le=120; 502/503 при недоступности
- backend/admin.py: GET /scraper/data-quality — single-pass FILTER-агрегаты по listings WHERE
  is_active GROUP BY source (description/photo_urls/address/lat/lon/kitchen_area_m2/living_area_m2/
  ceiling_height/ceiling_height_m/metro_stations); houses (total/avito_validated_at%/rating_score%/
  house_type%); house_reviews count
- browser/test_server_pacing.py: 10 новых тестов GET+PUT /pacing (16 total, все зелёные)
- backend/tests/test_scraper_admin_apis.py: тесты pacing-прокси + data-quality shape/pct-range
  (21 total, все зелёные)
lekss361 merged commit 93783602c5 into main 2026-06-20 12:31:48 +00:00
lekss361 deleted branch feat/scrapers-config-apis 2026-06-20 12:31:48 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1829
No description provided.