Развести окна ДомКлика: область не должна стартовать вместе с ЕКБ #3546

Merged
lekss361 merged 1 commit from fix/domclick-window-collision into main 2026-09-17 05:56:35 +00:00
Owner

Исправляет дефект, который я внёс миграцией 306 (#3545).

Что не так

306 поставила domclick_city_sweep_moskovskaya_oblast в окно 3-6 — ровно то же, где с самого начала сидит ЕКБ-строка domclick_city_sweep. Планировщик домклик-джобы не сериализует: 17.09 обе новые строки были заклеймлены в одну секунду (run 7333 и 7334, 05:00:55) и пошли параллельно.

3 | 6 | 2 | domclick_city_sweep, domclick_city_sweep_moskovskaya_oblast

Два свипа ДомКлика делят один браузерный сайдкар и один пул прокси. В минуты параллельного прогона tradein-browser держал 67% CPU, 1.67 из 2.5 ГиБ и 2297 PID, а часть запросов возвращалась как Page.goto: Timeout 60000ms и socket hang up → HTTP 500. Узлов с provider_affinity='any' в пуле всего два (id 13 и 14), их же берёт cian — параллельная пара домклик-свипов забирает оба.

Чего этот PR НЕ утверждает

Что параллельность уронила сбор. Померить это по ходу прогона нечем: DomClickScraper.fetch_city копит лоты в память и сохраняет их одним save_listings после обхода всех шести бакетов — инкрементального сохранения нет. Поэтому «ноль строк в listings за 45 минут» — нормальное состояние середины прогона, а не признак провала: здоровый одиночный ЕКБ-свип 16.09 (run 7219) тоже не писал ничего 70 минут и затем положил 6372 seen / 237 new.

Окна разводятся по ресурсной причине выше, а не по выводу из этой метрики. Изоляция настоящей причины (если она есть) — отдельным одиночным прогоном после того, как текущая пара завершится.

Что меняется

source было стало
domclick_city_sweep (ЕКБ) 3-6 3-6 (не трогаем)
domclick_city_sweep_moskva 0-3 0-3 (не трогаем)
domclick_city_sweep_moskovskaya_oblast 3-6 9-12

9-12 выбрано потому, что там нет ни одной домклик-строки: домклик-джоб всего три — domclick_city_sweep 3-6, domclick_city_sweep_moskva 0-3 и domclick_detail_backfill 15-18.

next_run_at выставлен явно и разнесён. Без этого строки сохранили бы значения, посчитанные при первом клейме (Москва 20.09 01:46, область 20.09 04:11 — внутри ЕКБ-окна 3-6), и коллизия повторилась бы через трое суток.

AT TIME ZONE 'UTC' стоит на результате выражения, а не только внутри: next_run_attimestamptz, а date_trunc от naive-времени вернул бы timestamp без зоны, и приведение поехало бы по таймзоне сессии.

Проверка

Сухой прогон на проде под BEGIN … ROLLBACK:

UPDATE 1
UPDATE 1
 domclick_city_sweep                    | 3 |  6 | 2026-09-17 05:50:50+00
 domclick_city_sweep_moskovskaya_oblast | 9 | 12 | 2026-09-20 09:30:00+00
 domclick_city_sweep_moskva             | 0 |  3 | 2026-09-20 00:30:00+00
ROLLBACK

tests/test_migration_numbering.py → 1 passed, 2 skipped. Номер сверен с forgejo/main через git ls-tree -r (последняя — 306).

Смежная находка, в этот PR не входит

У ДомКлика нет кооперативной отмены по бакетам: runs.is_cancelled проверяется только перед SERP-фазой (pipeline.py, run_domclick_city_sweep), тогда как avito/yandex/cian проверяют перед каждым якорем, а cian full-load — в on_bucket. Из-за этого повисший домклик-свип нельзя снять, он живёт до watchdog'а (11100 с ≈ 3 ч), удерживая прокси и сайдкар. Чинится тем же приёмом, что в cian full-load (колбэк on_bucketraise RuntimeError("cancelled")) — отдельной задачей.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs

Исправляет дефект, который я внёс миграцией 306 (#3545). ## Что не так 306 поставила `domclick_city_sweep_moskovskaya_oblast` в окно **3-6** — ровно то же, где с самого начала сидит ЕКБ-строка `domclick_city_sweep`. Планировщик домклик-джобы не сериализует: 17.09 обе новые строки были заклеймлены в одну секунду (run 7333 и 7334, 05:00:55) и пошли параллельно. ``` 3 | 6 | 2 | domclick_city_sweep, domclick_city_sweep_moskovskaya_oblast ``` Два свипа ДомКлика делят **один** браузерный сайдкар и **один** пул прокси. В минуты параллельного прогона `tradein-browser` держал 67% CPU, 1.67 из 2.5 ГиБ и 2297 PID, а часть запросов возвращалась как `Page.goto: Timeout 60000ms` и `socket hang up` → HTTP 500. Узлов с `provider_affinity='any'` в пуле всего два (id 13 и 14), их же берёт cian — параллельная пара домклик-свипов забирает оба. ## Чего этот PR НЕ утверждает Что параллельность уронила сбор. Померить это по ходу прогона нечем: `DomClickScraper.fetch_city` копит лоты в память и сохраняет их **одним** `save_listings` после обхода всех шести бакетов — инкрементального сохранения нет. Поэтому «ноль строк в `listings` за 45 минут» — нормальное состояние середины прогона, а не признак провала: здоровый одиночный ЕКБ-свип 16.09 (run 7219) тоже не писал ничего 70 минут и затем положил 6372 seen / 237 new. Окна разводятся по ресурсной причине выше, а не по выводу из этой метрики. Изоляция настоящей причины (если она есть) — отдельным одиночным прогоном после того, как текущая пара завершится. ## Что меняется | source | было | стало | |---|---|---| | `domclick_city_sweep` (ЕКБ) | 3-6 | 3-6 (не трогаем) | | `domclick_city_sweep_moskva` | 0-3 | 0-3 (не трогаем) | | `domclick_city_sweep_moskovskaya_oblast` | **3-6** | **9-12** | 9-12 выбрано потому, что там нет ни одной домклик-строки: домклик-джоб всего три — `domclick_city_sweep` 3-6, `domclick_city_sweep_moskva` 0-3 и `domclick_detail_backfill` 15-18. `next_run_at` выставлен **явно** и разнесён. Без этого строки сохранили бы значения, посчитанные при первом клейме (Москва 20.09 01:46, область 20.09 **04:11** — внутри ЕКБ-окна 3-6), и коллизия повторилась бы через трое суток. `AT TIME ZONE 'UTC'` стоит на результате выражения, а не только внутри: `next_run_at` — `timestamptz`, а `date_trunc` от naive-времени вернул бы `timestamp` без зоны, и приведение поехало бы по таймзоне сессии. ## Проверка Сухой прогон на проде под `BEGIN … ROLLBACK`: ``` UPDATE 1 UPDATE 1 domclick_city_sweep | 3 | 6 | 2026-09-17 05:50:50+00 domclick_city_sweep_moskovskaya_oblast | 9 | 12 | 2026-09-20 09:30:00+00 domclick_city_sweep_moskva | 0 | 3 | 2026-09-20 00:30:00+00 ROLLBACK ``` `tests/test_migration_numbering.py` → 1 passed, 2 skipped. Номер сверен с `forgejo/main` через `git ls-tree -r` (последняя — 306). ## Смежная находка, в этот PR не входит У ДомКлика нет кооперативной отмены по бакетам: `runs.is_cancelled` проверяется только **перед** SERP-фазой (`pipeline.py`, `run_domclick_city_sweep`), тогда как avito/yandex/cian проверяют перед каждым якорем, а cian full-load — в `on_bucket`. Из-за этого повисший домклик-свип нельзя снять, он живёт до watchdog'а (11100 с ≈ 3 ч), удерживая прокси и сайдкар. Чинится тем же приёмом, что в cian full-load (колбэк `on_bucket` → `raise RuntimeError("cancelled")`) — отдельной задачей. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs
lekss361 added 1 commit 2026-09-17 05:50:42 +00:00
fix(trade-in): развести окна ДомКлика — область не должна стартовать вместе с ЕКБ
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 14s
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 5m11s
dba508f5ce
Миграция 306 поставила domclick_city_sweep_moskovskaya_oblast в окно 3-6 —
ровно то же, где сидит ЕКБ-строка domclick_city_sweep. Планировщик домклик-джобы
не сериализует: 17.09 обе новые строки заклеймлены в одну секунду (run 7333 и
7334, 05:00:55) и пошли параллельно.

Два свипа ДомКлика делят один браузерный сайдкар и один пул. В минуты
параллельного прогона tradein-browser держал 67% CPU, 1.67 из 2.5 ГиБ и 2297 PID,
часть запросов возвращалась как Page.goto Timeout 60000ms и socket hang up.
Узлов с provider_affinity='any' всего два (id 13, 14), их же берёт cian.

Миграция НЕ утверждает, что параллельность уронила сбор: померить это по ходу
прогона нечем — fetch_city копит лоты в память и сохраняет одним save_listings
после всех шести бакетов, так что ноль строк в listings в середине прогона —
норма (здоровый одиночный ЕКБ-свип 16.09, run 7219, тоже молчал 70 минут и затем
положил 6372/237). Окна разводятся по ресурсной причине, а не по этой метрике.

Область → 9-12: там нет ни одной домклик-строки. Москва остаётся в 0-3.
next_run_at выставлен явно и разнесён — иначе сохранились бы значения первого
клейма (область 20.09 04:11, внутри ЕКБ-окна) и коллизия повторилась бы.

Проверено сухим прогоном на проде под ROLLBACK: UPDATE 1 + UPDATE 1, итоговые
окна 3-6 (ЕКБ) / 0-3 Москва 20.09 00:30 / 9-12 область 20.09 09:30.

Claude-Session: https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs
lekss361 merged commit 1db6612843 into main 2026-09-17 05:56:35 +00:00
lekss361 deleted branch fix/domclick-window-collision 2026-09-17 05:56:35 +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#3546
No description provided.