Сбой загрузки квартир глотается молча — провал /portal/table не пишется в kn_scrape_failures, run рапортует ложную полноту #1643

Closed
opened 2026-06-16 18:46:30 +00:00 by bot-backend · 0 comments
Collaborator

Severity: high · Категория: потеря данных / ложь в отчёте · Файл: backend/app/services/scrapers/domrf_kn.py:1456-1464, 1119-1127, 1866-1869

domrf_kn.py:1458-1462 — fetch_flats_for_object оборачивает sess.get_json(PATH_FLATS_TABLE) в try/except Exception и при ЛЮБОЙ ошибке (WAF-блок, 429, 5xx, timeout, non-JSON challenge) логирует logger.warning и возвращает []. Из-за этого обёртка _fetch_flats_safe (1124-1127) НИКОГДА не получает Exception: ветка return ('flats', url, e) на 1126-1127 фактически мёртвая — всегда возвращается ('flats', url, ). В цикле результатов (1861-1869) ветка kind_tag=='flats' делает только if flats_list: total_flats += upsert_flats(...), пустой список пропускается без записи. В отличие от ВСЕХ остальных endpoint'ов (sale_graph/sales_agg/infra/photos/docs), у которых исключение в tuple → result loop 1862-1864 → _classify_and_log (950) → _log_failure (985) → INSERT в kn_scrape_failures, провал квартир НЕ попадает в kn_scrape_failures вообще. Импакт: квартиры — основная сущность скрапера (#297). При WAF-блокировке /portal-kn/api/sales/portal/table все объекты молча дают [], total_flats не растёт, run завершается status='done' (2003-2006) с flats=N и пустой таблицей failures → ложь в админ-журнале + невидимая, неотслеживаемая для resume потеря данных. Фикс: убрать try/except внутри fetch_flats_for_object (пусть исключение поднимается → попадёт в _fetch_flats_safe.except → _classify_and_log), ЛИБО различать 'пусто' и 'сбой' (например возвращать None при ошибке) и логировать failure в kn_scrape_failures из ветки flats.

Почему баг: Квартиры — основная сущность скрапера (#297: '91% квартир без цены' было P0). Если DOM.РФ WAF-блокирует именно /portal/table (а warm_up даёт куки только для /api/object/*), все запросы квартир объекта молча дают [], total_flats не растёт, а run завершается status='done' с flats=N и пустой таблицей failures. Админ-журнал показывает 0 сбоев по квартирам даже при тотальной блокировке → ложь в отчёте + невидимая потеря данных, которую нельзя отследить для resume/повтора.

Как чинить: Не глотать ошибку внутри fetch_flats_for_object — пусть исключение поднимается до _fetch_flats_safe, который уже корректно кладёт его в tuple, и тогда _classify_and_log запишет failure. Либо явно пробрасывать признак сбоя (а не неотличимый пустой список) и логировать его в kn_scrape_failures. Также стоит отличать 'объект без квартир' (валидный []) от 'запрос упал'.


deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.9 · unit B31

**Severity:** high · **Категория:** потеря данных / ложь в отчёте · **Файл:** `backend/app/services/scrapers/domrf_kn.py:1456-1464, 1119-1127, 1866-1869` domrf_kn.py:1458-1462 — fetch_flats_for_object оборачивает sess.get_json(PATH_FLATS_TABLE) в try/except Exception и при ЛЮБОЙ ошибке (WAF-блок, 429, 5xx, timeout, non-JSON challenge) логирует logger.warning и возвращает []. Из-за этого обёртка _fetch_flats_safe (1124-1127) НИКОГДА не получает Exception: ветка return ('flats', url, e) на 1126-1127 фактически мёртвая — всегда возвращается ('flats', url, <list>). В цикле результатов (1861-1869) ветка kind_tag=='flats' делает только `if flats_list: total_flats += upsert_flats(...)`, пустой список пропускается без записи. В отличие от ВСЕХ остальных endpoint'ов (sale_graph/sales_agg/infra/photos/docs), у которых исключение в tuple → result loop 1862-1864 → _classify_and_log (950) → _log_failure (985) → INSERT в kn_scrape_failures, провал квартир НЕ попадает в kn_scrape_failures вообще. Импакт: квартиры — основная сущность скрапера (#297). При WAF-блокировке /portal-kn/api/sales/portal/table все объекты молча дают [], total_flats не растёт, run завершается status='done' (2003-2006) с flats=N и пустой таблицей failures → ложь в админ-журнале + невидимая, неотслеживаемая для resume потеря данных. Фикс: убрать try/except внутри fetch_flats_for_object (пусть исключение поднимается → попадёт в _fetch_flats_safe.except → _classify_and_log), ЛИБО различать 'пусто' и 'сбой' (например возвращать None при ошибке) и логировать failure в kn_scrape_failures из ветки flats. **Почему баг:** Квартиры — основная сущность скрапера (#297: '91% квартир без цены' было P0). Если DOM.РФ WAF-блокирует именно /portal/table (а warm_up даёт куки только для /api/object/*), все запросы квартир объекта молча дают [], total_flats не растёт, а run завершается status='done' с flats=N и пустой таблицей failures. Админ-журнал показывает 0 сбоев по квартирам даже при тотальной блокировке → ложь в отчёте + невидимая потеря данных, которую нельзя отследить для resume/повтора. **Как чинить:** Не глотать ошибку внутри fetch_flats_for_object — пусть исключение поднимается до _fetch_flats_safe, который уже корректно кладёт его в tuple, и тогда _classify_and_log запишет failure. Либо явно пробрасывать признак сбоя (а не неотличимый пустой список) и логировать его в kn_scrape_failures. Также стоит отличать 'объект без квартир' (валидный []) от 'запрос упал'. --- <sub>deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.9 · unit B31</sub>
bot-backend added the
week ревью 1
label 2026-06-16 18:46:30 +00:00
Sign in to join this conversation.
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#1643
No description provided.