gendesign/tradein-mvp/backend/data/sql/015_scrape_runs.sql
lekss361 28ddf6ef17 feat(tradein): SQL migrations 009-018 — houses + listings extension + history + IMV cache
Closes Stage 1 of AvitoScraper_v2 plan.

- 009_houses.sql: CREATE TABLE houses (multi-source: avito/cian, geom trigger, 24 cols)
- 010_houses_alter.sql: + 15 cols (material_walls, parking_type, rating_distribution, raw_characteristics, ...)
- 011_listings_alter.sql: + 24 cols (house linking, kitchen_area_m2, owners_count, owners_at_least,
  metro_stations, detail_enriched_at, domoteka/Rosreestr badges, 8 partial indexes)
- 012_sellers.sql: CREATE TABLE sellers (Avito seller cache, no logos)
- 013_listings_alter_seller.sql: listings.seller_id_fk FK
- 014_house_reviews.sql: CREATE TABLE house_reviews (textSections main/pros/cons, no images)
- 015_scrape_runs.sql: CREATE TABLE scrape_runs (status CHECK enum, heartbeat, zombie partial idx)
- 016_listings_snapshots.sql: CREATE TABLE listings_snapshots (append-only, PK listing_id+date)
- 017_house_placement_history.sql: CREATE TABLE house_placement_history (removed_date from IMV only)
- 018_avito_imv_evaluations.sql: CREATE TABLE + cache_key col + imv_cache_key_idx (TTL 24h lookup)

All migrations: BEGIN/COMMIT, IF NOT EXISTS idempotent, PostGIS geom triggers reuse listings_set_geom().
Smoke tested locally: 7 new tables, 34 indexes, 14 listings columns verified.

Refs: decisions/Schema_Avito_Houses_Listings_History.md (sec 4.2, 4.3, 4.4, 6, 7, 13, 25, 29)
Refs: decisions/AvitoScraper_v2_Implementation_Plan.md Stage 1
2026-05-23 14:29:04 +03:00

65 lines
3.3 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 015_scrape_runs.sql
-- CREATE TABLE scrape_runs — логирование scrape-сессий с heartbeat + lifecycle
--
-- Dependencies: нет (независимая таблица)
-- Apply after: 014_house_reviews.sql
-- Apply before: 016_listings_snapshots.sql
--
-- Source: decisions/Schema_Avito_Houses_Listings_History.md sec 4.3
-- Status enum: running / done / failed / zombie / skipped / banned
--
-- Паттерн совпадает с objective_scrape_runs из основной GenDesign БД.
-- Zombie detection: cron каждые 5 мин помечает runs где heartbeat_at < NOW() - 30 min.
--
-- Идемпотентно: безопасно запускать повторно.
BEGIN;
CREATE TABLE IF NOT EXISTS scrape_runs (
id bigserial PRIMARY KEY,
source text NOT NULL, -- 'avito' / 'cian' / ...
run_type text NOT NULL, -- 'search' / 'house_catalog' / 'detail' / 'imv'
-- Scope (для search runs — геометрия поиска)
anchor_lat double precision,
anchor_lon double precision,
radius_m int,
segment text, -- 'vtorichka' / 'novostroyki'
-- Scope (для house_catalog/detail runs)
target_ext_id text, -- house_id или item_id
-- Lifecycle
started_at timestamptz NOT NULL DEFAULT NOW(),
heartbeat_at timestamptz NOT NULL DEFAULT NOW(), -- обновляется каждые N сек в process loop
finished_at timestamptz,
status text NOT NULL DEFAULT 'running'
CHECK (status IN ('running','done','failed','zombie','skipped','banned')),
error_text text,
-- Counters (для аналитики и debugging)
total_seen int DEFAULT 0, -- кол-во объявлений в выдаче
new_count int DEFAULT 0, -- новых (не было в БД)
returning_count int DEFAULT 0, -- видели → пропали → снова видим
disappeared_count int DEFAULT 0, -- пропали (last_seen > cutoff после run)
-- HTTP stats (для мониторинга rate limits)
http_requests int DEFAULT 0,
http_errors int DEFAULT 0
);
CREATE INDEX IF NOT EXISTS scrape_runs_source_started_idx ON scrape_runs (source, started_at DESC);
-- Partial index для zombie detection (только 'running' статус)
CREATE INDEX IF NOT EXISTS scrape_runs_zombies_idx ON scrape_runs (status, heartbeat_at)
WHERE status = 'running';
COMMENT ON TABLE scrape_runs IS
'Лог scrape-сессий. Heartbeat обновляется в process loop. '
'Zombie: status=running AND heartbeat_at < NOW() - 30 min — помечается cron.';
COMMENT ON COLUMN scrape_runs.status IS
'Enum: running=активен, done=успех, failed=ошибка, zombie=heartbeat устарел, '
'skipped=нет новых данных, banned=Avito вернул 403/captcha.';
COMMENT ON COLUMN scrape_runs.returning_count IS
'Объявления которые пропадали (is_active=false) и снова появились в выдаче.';
COMMIT;