feat(scrape-kn): parallel Phase B/C + wire obj_checks + documents + is_ekb auto-derive #322
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#322
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/domrf-speedup-wire-extras"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
4-в-1 PR для
domrf_knscraperПосле активации Objective live API (PR #311/313/315/318/320/321) этот PR закрывает 4 dangling задачи DOM.РФ scraper'а:
1. ⚡ Speedup Phase B/C (~6× быстрее)
backend/app/services/scrapers/domrf_kn.py:1669-1787Было (run #14 stats: 12 526s / 1 516 obj = 3.5 ч, 8.3 sec/obj):
Стало —
asyncio.gatherвсех 6 (теперь 8) endpoints одногоobj_idпараллельно через_fetch_*_safewrappers.BrowserSession._sem(3)уже bounds concurrency. Ожидаемый speedup ~6×: 3.5 ч → ~35 мин для 1 532 объектов.2. 📄 Wire
documentsextractorPR #305 создал таблицу
domrf_kn_documents+ parserservices/scrapers/documents.py(готовыеextract_documents()+upsert_documents()), но scraper main loop их не импортировал. Таблица 0 rows.Этот PR:
extract_documents+upsert_documentsвdomrf_kn.py_fetch_documents_safe(sess, obj_id)wrapperasyncio.gatherPATH_DOCUMENTS = "/сервисы/api/object/{obj_id}/documents"(подтверждено per vaultFix_BUG22i)documents_rowsвextras_counts+ progress logПосле следующего sweep — заполнятся PDF docs (декларации, разрешения, проектные).
3. ✅ Create + wire
obj_checksextractorPR #303 создал таблицу
domrf_obj_checks(6 чекбоксов "Проверено на наш.дом.рф"), но extractor не существовал. Таблица 0 rows.Этот PR создаёт
backend/app/services/scrapers/obj_checks.py(~160 строк):CHECK_TYPES = ["no_problems", "docs", "timing", "photos", "bankruptcy", "declaration"]extract_obj_checks(payload)— поддерживает dict-format и list-format payloadsupsert_obj_checks(db, obj_id, checks)— SAVEPOINT per-rowdomrf_kn.pyparallel gather⚠️
PATH_CHECKS = "/сервисы/api/object/{obj_id}/checks"— endpoint URL не verified через devtools, derived from same/сервисы/api/object/namespace что у/infrastructure,/documents,/photos. Если после next sweep всё ещё 0 rows + 404 вkn_scrape_failuresдля всех objects → нужно devtools-inspect страницу ЖК и update constant. На failure — sweep продолжается, не падает.4. 🇪🇰🇧 Phase E —
is_ekbauto-deriveПосле Phase D finalize (~line 1652+) добавлена Phase E:
Best-effort: exception caught + logged, sweep всё равно завершается. Раньше требовался manual run после scrape.
Operations note
Run #18 (started 19:20Z, ETA 23:00Z) будет убит при deploy этого PR —
--force-recreate workerпересоздаёт контейнер, in-flight task dies. После deploy — manual re-trigger/admin/scrape/knсразу даст ~35-мин sweep вместо 3.5-час.User explicitly authorized kill #18 + retrigger с оптимизированной версией.
Acceptance после merge + deploy
domrf_kn_documentscount > 0 после первого sweep (or 404 вkn_scrape_failuresесли documents endpoint missing)domrf_obj_checkscount > 0 (or 404 → нужен fix endpoint URL)kn_scrape_logпосле Phase Dis_ekb=TRUEcount в свежем snapshot ~1300 (вся ЕКБ)obj_class/wall_type/energy_eff/flat_number↑ (применение PR #302 mapping fix)Tech debt outstanding (не в этом PR)
objective_lots.price_per_m2_rub(81%)photos=Falsedefault, тяжёлая операция (~1+ GB на регион). Опционально вкл через job_settings.Risk
_sem(3)semaphoreПосле deploy и первого sweep — verify endpoint via vault + adjust if needed.
Deep Code Review — verdict: APPROVE
Summary
domrf_kn.py,obj_checks.pynew)1db19b3Correctness — parallel Phase B/C
_fetch_*_safewrappers catchExceptionand return it in the result tuple — no exception bubbles up to abortasyncio.gather.return_exceptions=Falseis therefore safe.BrowserSession._sem = asyncio.Semaphore(3)(stealth.py:107) is acquired insideget_json()per-request (stealth.py:152), not at the outer fetcher level. Every parallel coroutine routes throughget_json→ bounded concurrency confirmed.gathercompletes (domrf_kn.py:1698+) — single Session, no parallel writes. Race-free.(sess, obj_id [, type_])only; accumulation intoextras_countshappens in the main coroutine post-gather._classify_and_log(db, run_id, obj_id, kind_tag, full_url, e)signature matches existing usage (domrf_kn.py:888).Correctness —
obj_checks.pywith db.begin_nested():— compliant with.claude/rules/backend.md.:obj_id,:check_type,:passed), no:x::typecasts, no f-string injection.extract_obj_checksdefensively handles both dict and list payloads with sensible warning + empty return on unknown shape — won't crash sweep.ON CONFLICT (obj_id, check_type) DO UPDATEis idempotent.db.commit()after the loop is consistent withdocuments.upsert_documents.Correctness — documents wiring
_fetch_documents_safe+ result dispatch correctly callupsert_documents(db, obj_id, docs) -> (int, int)and unpack onlyins.extras_counts["documents_rows"]initialised at line 1585, incremented at result dispatch — clean.Correctness — Phase E
is_ekb:snapplaceholder, no::datecast (already date type) — psycopg v3 clean.COALESCE(is_ekb, FALSE) = FALSEguard makes it idempotent across reruns.try/except + db.rollback() + log_progress(level="warn")— sweep continues on failure.Conventions
psycopg2, norequests, noprint(), no hardcoded creds, no f-string SQL.Cross-file impact
extras_countsdict gets two new keys (documents_rows,checks_rows) — local torun_region_sweep, returned in result dict additively. No consumer breakage.Minor observations (non-blocking)
_fetch_sale_graph_safeetc. return tuples like(rows, url)even though the dispatcher only needsrows—urlis captured both in the wrapper tuple and the inner result tuple. Cosmetic only.PATH_CHECKS = "/сервисы/api/object/{obj_id}/checks"is unverified per author note. Acceptable trade-off: graceful 404 logged intokn_scrape_failuresvia_classify_and_log, sweep continues. If endpoint is wrong, first sweep will produce 1500+ WARN entries inkn_scrape_failures— verify post-deploy via SQL and adjust the constant if needed.Risk
/admin/scrape/knafter deploy as author noted.Merging.