fix(obj-2): trim migration 116 to GIST index only — INSERT CTE timed out in deploy #326
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#326
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/116-deploy-timeout-hotfix"
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?
Hotfix
Deploy завис на migration
116_obj2_multi_feature_matcher.sql:Root cause
Original INSERT (CROSS JOIN LATERAL
similarity()на 1056 unmapped DOM.РФ × 320 distinct Objective projects × top-3) — 89M cost (раньше worker через EXPLAIN видел перед kill'ом).GIST trgm index уже добавился в первом шаге, но INSERT с heavy CTE завис.
Fix
Trim миграция → только
CREATE INDEX IF NOT EXISTS. Multi-feature INSERT уже частично применён inline 2026-05-17 (+13 mappings: 129 → 142).Полный backfill через отдельную миграцию 117 с pre-materialized temp tables (вместо full LATERAL scan) — после EXPLAIN ANALYZE re-tuning.
Why это safe
CREATE INDEX IF NOT EXISTSидемпотентен — если index уже есть (как сейчас в проде после первого partial apply), skipped без ошибкиVerify after deploy
Part of issue #307 OBJ-2.
Deep Code Review — verdict: APPROVE
Status: APPROVE (hotfix fast-track)
Files: 1 (P0:
data/sql/116_obj2_multi_feature_matcher.sql)Lines: +10 / -91
Diff verified
CREATE INDEX IF NOT EXISTS objective_lots_project_name_trgm_idx ON objective_lots USING gist (project_name gist_trgm_ops);Re-application safety (critical question answered)
Read
.forgejo/workflows/deploy.ymllines 225–248. Apply step:for sql_file in $(ls data/sql/*.sql | sort) ..._schema_migrations WHERE filename=$fname→ if 0, runpsql < $sql_file -v ON_ERROR_STOP=onINSERT INTO _schema_migrationsmark it applied.Therefore original 116 (which timed out / never exited cleanly) is NOT marked applied → trimmed 116 will re-run on next deploy.
Lock / impact analysis
CREATE INDEX(non-CONCURRENTLY) normally takes AccessExclusiveLock onobjective_lots. However, prod deploy log already showsNOTICE: relation "objective_lots_project_name_trgm_idx" already exists, skipping. WithIF NOT EXISTS, when index exists this becomes a metadata-only no-op (no rebuild, no exclusive lock on table heap). Net effect on next deploy: instant skip → mark applied → migration loop continues to 117+.objective_lotsis a small reference table (~few hundred K rows at most for EKB Objective lots scope) — index build is sub-second range. Acceptable.REFRESH MV removal — safe
Other consumers (
backend/app/api/v1/parcels.py,services/site_finder/best_layouts.py,layout_velocity_refresh.py) READmv_layout_velocity. Since the trimmed migration inserts no new mapping rows, the MV's underlying data is unchanged → refresh is unnecessary. Refresh is also performed routinely bylayout_velocity_refresh.py, so even drift would self-heal.Risk score
Why not BLOCK on non-CONCURRENTLY CREATE INDEX
Normally I'd flag CREATE INDEX without CONCURRENTLY on prod, but here:
Merging now.