chore(tradein/db): снести три колонки-заглушки из витрины поиска (#2857) #2858
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
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#2858
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "chore/2857-drop-placeholder-columns"
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?
Summary
Витрина поиска
listings_search_mvс миграции 050 отдавала четыре колонки, заданные литераломNULLпрямо в определении. Три из них —distance_to_metro_m,last_price_change,photos_count— сняты миграцией 261.districtне тронут: он объявлен вschemas/search_response.py, API его отдаёт, и его снос — ломающее изменение контракта (решение владельца, вынесено в #2857 отдельно).Правок кода нет: у трёх колонок ноль читателей.
Читателей действительно ноль — перепроверено на
origin/maingit grep -E "distance_to_metro_m|last_price_change|photos_count" origin/main050/094(объявление + комментарий над ним)SELECT *из витрины где угодно в репоservices/search_query.pypg_depend/pg_rewrite)Гранты (главная ловушка — C3, FDW-гранты после
DROP ... CASCADE)information_schema.role_table_grantsпо витрине пуст всегда и ничего не доказывает: information_schema не показывает материализованные представления в принципе. Смотреть надоpg_class.relacl.Прод, до правки:
relacl = {tradein=arwdDxt/tradein}— только владелец. Колоночных грантов нет,pg_default_aclпуст. Для сравнения:gendesign_readerимеет SELECT наlistingsиoffer_price_history— на витрину ему не давали. Восстанавливать сегодня нечего.Тем не менее ACL снимается и переигрывается в той же транзакции: между написанием файла и деплоем может пройти неделя, и ручной слепок протухнет молча. Первая редакция блока теряла колоночные гранты (
pg_attribute.attaclживёт не вrelacl) — поймано прогоном на одноразовой БД, исправлено.Индексы
Все 6 воссоздаются один в один (
050/094, сверено с прод-каталогом). UNIQUElistings_search_mv_id_idx (listing_id)обязателен: без него ночнойREFRESH MATERIALIZED VIEW CONCURRENTLY(refresh_search_matview, 03:00-04:00 UTC) падает — и молчит до самой ночи. Отдельный тест краснеет, если индекс исчезнет из определения.Цена пересоздания
Транзакция держит ACCESS EXCLUSIVE от
DROPдоCOMMIT. Замер на проде: тело витрины — 6.6 s (EXPLAIN ANALYZE, прогретый кэш), плюс 6 индексов (GIN tsv 19 МБ + GIN trgm 17 МБ приmaintenance_work_mem64 МБ) → ориентир 30-60 s. Приемлемо: за всю жизнь БД (stats_resetпуст) витрина видела 225 seq_scan и 63 idx_scan, причём суточный CONCURRENTLY-рефреш сам даёт по seq_scan в день — то есть/api/v1/searchк ней практически не ходит. Трюк «собрать под временным именем + переименовать» не нужен.Если деплой попадёт в окно 03:00-04:00 UTC,
DROPстолкнётся с рефрешем →lock_timeout5 s → честный красный деплой, миграция не помечается применённой, повторный деплой пройдёт.Test plan
scripts/check-migration-lock-timeout.py→✓ блокирующий DDL прикрыт lock_timeout (проверено новых миграций: 11)origin/main:1 failed, 3 passed—listings_search_mv снова отдаёт колонки-заглушки ['distance_to_metro_m', 'last_price_change', 'photos_count']. Ветка:4 passed. Тест смотрит на состав списка колонок, разобранного из актуального определения витрины, а не на подстроку: переформатирование SQL илиNULL::int→NULL::integerего не трогают.districtна месте (attnum 29); индексов 6;REFRESH MATERIALIZED VIEW CONCURRENTLYпроходит; точный SELECT изsearch_query.pyвыполняется; повторный прогон того же файла — идемпотентен.GRANT SELECT+GRANT SELECT (listing_id, address) WITH GRANT OPTIONдляgendesign_reader→ после миграцииrelaclи обаattaclвосстановлены байт-в-байт ({gendesign_reader=r*/tradein}).ALTER MATERIALIZED VIEW ... DROP COLUMNиALTER TABLE <matview> DROP COLUMNоба отвечаютERROR: ALTER action DROP COLUMN cannot be performed ... This operation is not supported for materialized views— отсюда пересоздание.test_migrations_manifest.py— 4 passed (файл дописан в_manifest_applied.txt).261_...sqlв_schema_migrations; 31 колонка;pg_matviews.definitionбезdistance_to_metro_m;relaclэквивалентен доприменительному; ночнойrefresh_search_matview→status='done'; ответ/api/v1/searchпо-прежнему содержит ключdistrict.Критерий приёмки записан в шапке миграции, до применения.
Refs #2857
Проверил утверждение, которое несёт всю проверку грантов — оно верно
Вы опровергли мою инструкцию по существу, и это стоит зафиксировать, потому что ошибка была бы тихой.
Контраст решающий: у таблицы
listingsгрант читателю есть и виден, у витрины его нет. Но если бы он был —information_schemaвсё равно показал бы ноль, потому что материализованные представления она не отображает в принципе. То есть ноль там верен случайно, а не потому, что грантов нет: тот самый четвёртый вид нуля, где не состоялся сам замер.Проверять ACL матвьюх — только через
pg_class.relaclплюсpg_attribute.attaclдля колоночных.Отдельно — про вашу собственную поправку
То, что первая редакция блока восстановления читала только
relaclи молча теряла колоночные гранты, вы нашли не рассуждением, а прогоном: выдалиGRANT SELECT (listing_id, address) ... WITH GRANT OPTIONна одноразовой БД и посмотрели, что осталось после. Это ровно правильный ход — придумать состояние, при котором правка обязана сломаться, и проверить, ломается ли.Блок восстановления оставлен, хотя восстанавливать сегодня нечего, — верно: ручной слепок протухает молча, а миграция едет на прод через неопределённое время.
Мои числа, которые вы поправили
districtиcadastral_number. Последняя не заглушка, а живая колонка с писателем, которой площадки не отдают данных. 41 относится к другим объектам эпика.Мой след, который вы заметили
260_houses_drop_has_panorama.sqlвнутри шапки называет себя259_— это моё переименование вчера при коллизии номеров: два независимых PR взяли 259, я переименовал второй в 260 вместе со ссылкой в тесте и записью в манифесте, а комментарий в шапке пропустил. Правильно, что не тронули чужой применённый файл; поправлю отдельно.Смержено: CI зелёный 8/8,
running— 0 строк, процессов сбора 0.