All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 13s
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 4m54s
Обе миграции создавали индекс без транзакции и без SET LOCAL lock_timeout. Гейт scripts/check-migration-lock-timeout.py это и поймал: ::error 276_landing_showcase_deals.sql:: блокирующий DDL без lock_timeout (CREATE INDEX IF NOT EXISTS idx_landing_showcase_deals_computed_at ...) Обе обёрнуты в BEGIN + SET LOCAL lock_timeout = '5s' + COMMIT по образцу 272_houses_region_code.sql. Локально гейт зелёный: «проверено новых миграций: 31».
50 lines
3.3 KiB
PL/PgSQL
50 lines
3.3 KiB
PL/PgSQL
-- 276: витрина лэндинга на РЕАЛЬНЫХ сделках (issue B2C-showcase).
|
||
--
|
||
-- ЗАЧЕМ ТАБЛИЦА, А НЕ ВЫЧИСЛЕНИЕ В РУЧКЕ. Прогноз считается полным спайном
|
||
-- оценщика: несколько пространственных SELECT'ов на КАЖДУЮ сделку. Двадцать
|
||
-- сделок — это сотни запросов; на публичной ручке без авторизации это готовый
|
||
-- рычаг для DoS. Поэтому пересчёт — офлайн-задача (app/tasks/landing_showcase_deals.py),
|
||
-- ручка читает готовые строки.
|
||
--
|
||
-- ЧЕГО ЗДЕСЬ НАМЕРЕННО НЕТ — АДРЕСА. В `deals` номер дома есть у 2.7% строк
|
||
-- (620 различных адресов на 24 644 сделки), то есть «улица + дом» на витрине
|
||
-- была бы додумана. Показываем район + характеристики квартиры; улицы нет
|
||
-- даже колонкой, чтобы её нельзя было «на минутку» вывести.
|
||
--
|
||
-- deal_quarter — ТЕКСТ КВАРТАЛА, не дата: `deals.deal_date` принимает всего 10
|
||
-- различных значений на всю таблицу (первое число квартала), то есть дня
|
||
-- сделки в данных нет. Хранить date здесь значило бы отдать фронту точность,
|
||
-- которой не существует.
|
||
--
|
||
-- district и floor — NULLABLE. Район резолвится через FDW-вьюху чужой базы
|
||
-- (gendesign_ekb_districts_geom), и её гранты уже терялись (см. C3); floor в
|
||
-- части ДКП-строк пуст. Правило проекта: нет величины — пишем NULL, а не
|
||
-- правдоподобное значение. Отбор в задаче ранжирует такие строки ниже, но не
|
||
-- запрещает их: пустая витрина хуже витрины без района.
|
||
BEGIN;
|
||
-- Конвенция проекта (#2752): блокирующий DDL идёт под lock_timeout, иначе он
|
||
-- встанет в очередь за чужой сессией и утащит за собой запросы приложения.
|
||
SET LOCAL lock_timeout = '5s';
|
||
|
||
CREATE TABLE IF NOT EXISTS landing_showcase_deals (
|
||
id bigserial PRIMARY KEY,
|
||
computed_at timestamptz NOT NULL DEFAULT now(),
|
||
district text,
|
||
rooms integer NOT NULL,
|
||
area_m2 numeric(8, 2) NOT NULL,
|
||
floor integer,
|
||
total_floors integer,
|
||
deal_quarter text NOT NULL,
|
||
predicted_rub bigint NOT NULL,
|
||
fact_rub bigint NOT NULL,
|
||
err_pct numeric(6, 2) NOT NULL,
|
||
n_analogs integer NOT NULL,
|
||
note text NOT NULL
|
||
);
|
||
|
||
-- Ручка всегда читает ПОСЛЕДНИЙ пересчёт (max computed_at) — старые батчи
|
||
-- остаются для сверки «что показывали неделю назад».
|
||
CREATE INDEX IF NOT EXISTS idx_landing_showcase_deals_computed_at
|
||
ON landing_showcase_deals (computed_at DESC);
|
||
|
||
COMMIT;
|