From 9ffeee7ed2c45602145d20745d10bea17f0c885b Mon Sep 17 00:00:00 2001 From: lekss361 Date: Sun, 17 May 2026 23:38:22 +0000 Subject: [PATCH] =?UTF-8?q?feat(22d):=20admin=20UI=20buttons=20(skip/force?= =?UTF-8?q?)=20+=20reduce=20catalog=20jitter=20800=E2=86=92300ms=20(#352)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/scrapers/domrf_catalog_object.py | 4 +- frontend/src/app/admin/scrape/page.tsx | 141 ++++++++++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/backend/app/services/scrapers/domrf_catalog_object.py b/backend/app/services/scrapers/domrf_catalog_object.py index 4e782a0e..1bc58d7d 100644 --- a/backend/app/services/scrapers/domrf_catalog_object.py +++ b/backend/app/services/scrapers/domrf_catalog_object.py @@ -190,7 +190,7 @@ async def fetch_catalog_object_html(session: BrowserSession, obj_id: int) -> str for attempt in range(5): async with session._sem: - await jitter_sleep(800, 1500) + await jitter_sleep(300, 700) try: session._request_count += 1 result = await session._page.evaluate(_FETCH_HTML_JS, {"url": url}) @@ -412,7 +412,7 @@ async def scrape_catalog_objects( ) -> dict[str, int]: """Scrape списка объектов через один BrowserSession. - Запускает один BrowserSession на весь batch; jitter_sleep (800–1500 мс) + Запускает один BrowserSession на весь batch; jitter_sleep (300–700 мс) встроен в fetch_catalog_object_html для защиты от rate-limit. Returns: diff --git a/frontend/src/app/admin/scrape/page.tsx b/frontend/src/app/admin/scrape/page.tsx index 187e075b..38d18b4f 100644 --- a/frontend/src/app/admin/scrape/page.tsx +++ b/frontend/src/app/admin/scrape/page.tsx @@ -26,6 +26,13 @@ interface TriggerResp { developers: string[] | null; } +interface CatalogTriggerResp { + task_id: string; + region_code: number; + max_objects: number | null; + force: boolean; +} + interface QueueTask { worker: string; task_id: string; @@ -78,6 +85,7 @@ export default function ScrapeAdminPage() { const [extras, setExtras] = useState(true); const [downloadPhotos, setDownloadPhotos] = useState(false); const [forceRun, setForceRun] = useState(false); + const [catalogMaxObjects, setCatalogMaxObjects] = useState(""); const [showFailures, setShowFailures] = useState(false); const [failuresRunId, setFailuresRunId] = useState(""); const [logsRunId, setLogsRunId] = useState(""); @@ -121,6 +129,27 @@ export default function ScrapeAdminPage() { }, }); + const catalogTrigger = useMutation({ + mutationFn: (force: boolean) => + apiFetch("/api/v1/admin/scrape/kn-catalog-objects", { + method: "POST", + headers: { "X-Admin-Token": token }, + body: JSON.stringify({ + region_code: region, + max_objects: catalogMaxObjects === "" ? null : catalogMaxObjects, + force, + }), + }), + onSuccess: (data) => { + console.log("[scrape] catalog queued:", data); + queryClient.invalidateQueries({ queryKey: ["scrape-runs"] }); + queryClient.invalidateQueries({ queryKey: ["scrape-queue"] }); + }, + onError: (err) => { + console.error("[scrape] catalog failed:", err); + }, + }); + const releaseLock = useMutation({ mutationFn: () => apiFetch<{ @@ -458,6 +487,118 @@ export default function ScrapeAdminPage() { ) : null} +
+

📦 Catalog-object (SSR)

+

+ Заполняет wall_type, energy_eff, ceiling_height_m, parking_*, + playground_*, scores из публичной страницы каталога DOM.РФ. По + умолчанию пропускает объекты, обновлённые сегодня. +

+
+ + + +
+ {catalogTrigger.isError ? ( +
+ Ошибка: {String(catalogTrigger.error)} +
+ ) : null} + {catalogTrigger.isSuccess ? ( +
+ ✓ Catalog-object queued. task_id={" "} + + {catalogTrigger.data.task_id} + {" "} + · регион {catalogTrigger.data.region_code} · force={" "} + {String(catalogTrigger.data.force)} · max_objects={" "} + {catalogTrigger.data.max_objects ?? "default"} +
+ ) : null} +
+