fix(ptica): бан НСПД по WAF больше не глотается сборщиком кварталов (#2464-A) #2881

Merged
bot-backend merged 1 commit from fix/2464-waf-swallow-harvest into main 2026-08-14 06:00:11 +00:00
Collaborator

Что

harvest_quarter обещает в докстроке:

Raises:
    NspdBulkWafError: при WAF 403 — caller не retry.
    NspdBulkRateLimitError: при исчерпании retries — caller может retry.

Три голых except Exception это обещание отменяли. NspdBulkWafError наследуется от
NspdBulkError(RuntimeError), поэтому широкий обработчик ловил его наравне с сетевым
таймаутом и превращал бан IP в «этот cell/слой не дошёл». Обход продолжался, job доходил
до status='done' с частичными данными.

Замер на проде

cadastre_jobs, 13.08:

job'ов                     23
done                       12
failed                      0     ← ни одного
WAF-блоков суммарно        50     (в одном job'е)
последний job     2026-06-19

50 WAF-блоков и ноль упавших job'ов. Контракт обещает остановку, а на практике бан ни
разу сбор не остановил.

Как

Три сайта, во всех — except (NspdBulkWafError, NspdBulkRateLimitError): raise перед
широкими обработчиками:

Строка Что Было
:185 per-category probe search_by_quarter бан → «этот cat не дошёл», continue
:282 get_territorial_zones_in_bbox бан → «слой пуст», предупреждение в лог
:402 цикл ячеек в _grid_walk_category бан → «этот cell не дошёл», continue

Зеркало уже исправленных nspd_bulk_client.get_features_in_bbox_grid (Issue #252-mirror)
и nspd_client.get_features_in_bbox_grid (#2464-G, вчерашний PR #2873).

Продолжать обход после 403 вредно вдвойне: углубляет бан и дописывает в БД ложный
нулевой слой
, неотличимый от честного «здесь ничего нет».

Обработчик геометрии на :265 не тронут — там DB-исключение (ST_GeomFromGeoJSON на
битом GeoJSON), а не сеть.

Проверка

Тесты двусторонние. Против bulk_harvest.py из main:

2 failed, 1 passed
    FAILED test_grid_walk_reraises_waf_instead_of_swallowing
    FAILED test_grid_walk_reraises_rate_limit
    passed test_grid_walk_still_tolerates_network_error_per_cell   ← контроль
после правки: 3 passed

Третий тест — намеренный контроль обратной крайности: OSError в ячейке обход не
роняет и layer_failed не поднимает. Зелёный с обеих сторон.

  • pytest tests/services/test_cadastre_bulk.py — 60 passed
  • ruff check — clean

Чего не смог измерить

Хотел разложить тот единственный job с 50 блоками по строкам (job_id, длительность,
сколько кварталов успело собраться до бана) — SSH к прод-хосту в этот момент отвалился
(No route to host, потом восстановился). Агрегат выше снят до обрыва и достаточен для
вывода; детализация — если понадобится, отдельно.

Refs #2464

## Что `harvest_quarter` обещает в докстроке: ``` Raises: NspdBulkWafError: при WAF 403 — caller не retry. NspdBulkRateLimitError: при исчерпании retries — caller может retry. ``` Три голых `except Exception` это обещание отменяли. `NspdBulkWafError` наследуется от `NspdBulkError(RuntimeError)`, поэтому широкий обработчик ловил его наравне с сетевым таймаутом и превращал бан IP в «этот cell/слой не дошёл». Обход продолжался, job доходил до `status='done'` с частичными данными. ## Замер на проде `cadastre_jobs`, 13.08: ``` job'ов 23 done 12 failed 0 ← ни одного WAF-блоков суммарно 50 (в одном job'е) последний job 2026-06-19 ``` **50 WAF-блоков и ноль упавших job'ов.** Контракт обещает остановку, а на практике бан ни разу сбор не остановил. ## Как Три сайта, во всех — `except (NspdBulkWafError, NspdBulkRateLimitError): raise` **перед** широкими обработчиками: | Строка | Что | Было | |---|---|---| | `:185` | per-category probe `search_by_quarter` | бан → «этот cat не дошёл», `continue` | | `:282` | `get_territorial_zones_in_bbox` | бан → «слой пуст», предупреждение в лог | | `:402` | цикл ячеек в `_grid_walk_category` | бан → «этот cell не дошёл», `continue` | Зеркало уже исправленных `nspd_bulk_client.get_features_in_bbox_grid` (Issue #252-mirror) и `nspd_client.get_features_in_bbox_grid` (#2464-G, вчерашний PR #2873). Продолжать обход после 403 вредно вдвойне: **углубляет бан** и **дописывает в БД ложный нулевой слой**, неотличимый от честного «здесь ничего нет». Обработчик геометрии на `:265` не тронут — там DB-исключение (`ST_GeomFromGeoJSON` на битом GeoJSON), а не сеть. ## Проверка Тесты двусторонние. Против `bulk_harvest.py` из main: ``` 2 failed, 1 passed FAILED test_grid_walk_reraises_waf_instead_of_swallowing FAILED test_grid_walk_reraises_rate_limit passed test_grid_walk_still_tolerates_network_error_per_cell ← контроль после правки: 3 passed ``` Третий тест — намеренный контроль обратной крайности: `OSError` в ячейке обход **не** роняет и `layer_failed` **не** поднимает. Зелёный с обеих сторон. - [x] `pytest tests/services/test_cadastre_bulk.py` — 60 passed - [x] `ruff check` — clean ## Чего не смог измерить Хотел разложить тот единственный job с 50 блоками по строкам (`job_id`, длительность, сколько кварталов успело собраться до бана) — SSH к прод-хосту в этот момент отвалился (`No route to host`, потом восстановился). Агрегат выше снят до обрыва и достаточен для вывода; детализация — если понадобится, отдельно. Refs #2464
bot-backend added 1 commit 2026-08-14 02:00:40 +00:00
fix(ptica): бан НСПД по WAF больше не глотается сборщиком кварталов
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m58s
CI / backend-tests (pull_request) Successful in 16m9s
CI / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
d2cf7456d9
harvest_quarter в докстроке обещает `Raises: NspdBulkWafError — caller не
retry`, но три голых `except Exception` это обещание отменяли: WAF-бан
превращался в «этот cell/слой не дошёл», обход продолжался и job доходил
до status='done' с частичными данными.

Прод-замер 13.08 по cadastre_jobs: 23 job'а, суммарно 50 WAF-блоков,
упавших — 0. То есть бан ни разу не остановил сбор, как обещано.

Три сайта: per-category probe (search_by_quarter), territorial_zones и
цикл ячеек в _grid_walk_category. Везде добавлен
`except (NspdBulkWafError, NspdBulkRateLimitError): raise` ПЕРЕД широкими
обработчиками — зеркало уже исправленных
nspd_bulk_client.get_features_in_bbox_grid и nspd_client (#2464-G).

Продолжать обход после 403 вредно вдвойне: углубляет бан и дописывает в БД
ложный нулевой слой, неотличимый от честного «здесь ничего нет».

Тесты двусторонние: против bulk_harvest из main падают ровно два новых
(waf, rate_limit), третий — контроль «сетевая ошибка ячейки обход НЕ
роняет и НЕ поднимает layer_failed» — зелёный с обеих сторон.

Refs #2464
bot-backend merged commit b0776cd01d into main 2026-08-14 06:00:11 +00:00
bot-backend deleted branch fix/2464-waf-swallow-harvest 2026-08-14 06:00:11 +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#2881
No description provided.