Чистый старт БД падает на миграции 077: FDW-backfill выполняется до создания USER MAPPING #2990

Closed
opened 2026-08-20 17:47:48 +00:00 by lekss361 · 2 comments
Owner

Эпик: #2989 · Блокер переезда — обнаружить это в окне будет дорого.

Находка

backend/data/sql/077_dedup_hash_plain_key_backfill.sql читает foreign table через postgres_fdw. А USER MAPPING создаёт бэкенд при старте — backend/app/core/fdw.py:68, то есть после initdb.

Схема на проде применяется через docker-entrypoint-initdb.d при первом старте тома. На чистом сервере initdb упадёт на 077 и контейнер не поднимется.

Почему это не всплывало: путь «пустой том» на реальном железе никогда не исполнялся — прод-том создан один раз и с тех пор живёт. А CI (.forgejo/workflows/ci-tradein.yml:157-160) этот файл явно пропускает, то есть гейт, который должен был поймать, специально ослаблен.

Что делать

Самый дешёвый фикс (найден при перепроверке): перестать монтировать backend/data/sql в /docker-entrypoint-initdb.d и применять схему отдельным шагом деплоя после compose up -d. Тогда сеть и FDW уже доступны, приложение успевает создать USER MAPPING до прогона, и ветка baseline в deploy-tradein.yml:702-717 перестаёт зависеть от невидимого побочного эффекта initdb.

Сама 077 — одноразовый backfill исторических dedup_hash, на пустой БД бессмысленна по определению; в новую цепочку не включать.

Acceptance

  • Схема применяется шагом деплоя, а не через docker-entrypoint-initdb.d
  • 077 удалена из backend/data/sql/, исключение снято в ci-tradein.yml:157-160 (иначе CI молча пропускает несуществующий файл и гейт теряет смысл)
  • Генеральная репетиция на новом сервере: пустой том, отдельный compose-проект, контейнер доходит до database system is ready to accept connections
  • Проверка невалидных индексов перенесена из деплоя в CI — при сборке 255 индексов в окне вероятность оборвать один заметно выше обычного

Scope: backend/data/sql/, .forgejo/workflows/ci-tradein.yml, docker-compose.prod.yml, deploy-tradein.yml.

Эпик: #2989 · **Блокер переезда — обнаружить это в окне будет дорого.** ## Находка `backend/data/sql/077_dedup_hash_plain_key_backfill.sql` читает foreign table через `postgres_fdw`. А `USER MAPPING` создаёт бэкенд при старте — `backend/app/core/fdw.py:68`, то есть **после** `initdb`. Схема на проде применяется через `docker-entrypoint-initdb.d` при первом старте тома. На чистом сервере `initdb` упадёт на 077 и контейнер не поднимется. Почему это не всплывало: путь «пустой том» на реальном железе **никогда не исполнялся** — прод-том создан один раз и с тех пор живёт. А CI (`.forgejo/workflows/ci-tradein.yml:157-160`) этот файл **явно пропускает**, то есть гейт, который должен был поймать, специально ослаблен. ## Что делать Самый дешёвый фикс (найден при перепроверке): **перестать монтировать `backend/data/sql` в `/docker-entrypoint-initdb.d`** и применять схему отдельным шагом деплоя после `compose up -d`. Тогда сеть и FDW уже доступны, приложение успевает создать `USER MAPPING` до прогона, и ветка baseline в `deploy-tradein.yml:702-717` перестаёт зависеть от невидимого побочного эффекта `initdb`. Сама 077 — одноразовый backfill исторических `dedup_hash`, на пустой БД бессмысленна по определению; в новую цепочку не включать. ## Acceptance - [ ] Схема применяется шагом деплоя, а не через `docker-entrypoint-initdb.d` - [ ] 077 удалена из `backend/data/sql/`, исключение снято в `ci-tradein.yml:157-160` (иначе CI молча пропускает несуществующий файл и гейт теряет смысл) - [ ] Генеральная репетиция на новом сервере: пустой том, отдельный compose-проект, контейнер доходит до `database system is ready to accept connections` - [ ] Проверка невалидных индексов перенесена из деплоя в CI — при сборке 255 индексов в окне вероятность оборвать один заметно выше обычного Scope: `backend/data/sql/`, `.forgejo/workflows/ci-tradein.yml`, `docker-compose.prod.yml`, `deploy-tradein.yml`.
lekss361 added the
bug
ci
priority/p1
scope/devops
tradein
labels 2026-08-20 17:50:51 +00:00
Collaborator

Ревизия acceptance — на 27.08.2026

1. «Схема применяется шагом деплоя, а не через docker-entrypoint-initdb.d» — решено иначе, пункт снят.

Дефект был не в самом монтировании, а в 077: она читала foreign table до того, как бэкенд создаст USER MAPPING. Фикс сделан в самой миграции — 077 выходит раньше обращения к FDW, если мигрировать нечего (pg_user_mappings пуст). Плюс TRADEIN_PG_INITDB_DIR (#2989) даёт на первом старте нового хоста подсунуть пустой каталог, если схема приезжает восстановлением дампа.

Переписывать деплой ради этого больше нечего чинить: путь initdb на пустом томе теперь проходит целиком — см. п.3.

2. «077 удалена, исключение снято в ci-tradein.yml» — сделано (исключение снято; файл оставлен с guard'ом).

Исключений в цикле CI больше нет, гейт катает все 252 файла подряд с ON_ERROR_STOP=onci-tradein.yml:182-191. 077 не удалена, а обезврежена: на пустой БД она сама печатает NOTICE и выходит. Удаление файла оставило бы дырку в нумерации и потеряло бы backfill для существующих инсталляций.

3. «Генеральная репетиция на новом сервере» — прогнана на реальном железе (Poincare).

Отдельный compose-проект, пустой том, весь backend/data/sql смонтирован в initdb.d:

готов на итерации 2
status=running  exit=0
ошибок в логе: 0
таблиц 73, индексов 250, невалидных 0
NOTICE:  077: USER MAPPING для gendesign_remote нет — backfill пропущен
database system is ready to accept connections

Тестовый контейнер и том удалены после прогона.

4. «Проверка невалидных индексов перенесена из деплоя в CI» — PR #3150.

Продублирована, не перенесена — обоснование в описании PR: CI собирает схему с нуля и по построению не воспроизводит оборванный CIC на живой базе, так что снятие проверки из деплоя было бы регрессией #2752. Оба пути гейта прогнаны на реальной базе.

Закрываю после мержа #3150.

## Ревизия acceptance — на 27.08.2026 **1. «Схема применяется шагом деплоя, а не через `docker-entrypoint-initdb.d`» — решено иначе, пункт снят.** Дефект был не в самом монтировании, а в 077: она читала foreign table до того, как бэкенд создаст `USER MAPPING`. Фикс сделан в самой миграции — 077 выходит раньше обращения к FDW, если мигрировать нечего (`pg_user_mappings` пуст). Плюс `TRADEIN_PG_INITDB_DIR` (#2989) даёт на первом старте нового хоста подсунуть пустой каталог, если схема приезжает восстановлением дампа. Переписывать деплой ради этого больше нечего чинить: путь `initdb` на пустом томе теперь проходит целиком — см. п.3. **2. «077 удалена, исключение снято в `ci-tradein.yml`» — сделано (исключение снято; файл оставлен с guard'ом).** Исключений в цикле CI больше нет, гейт катает все 252 файла подряд с `ON_ERROR_STOP=on` — `ci-tradein.yml:182-191`. 077 не удалена, а обезврежена: на пустой БД она сама печатает `NOTICE` и выходит. Удаление файла оставило бы дырку в нумерации и потеряло бы backfill для существующих инсталляций. **3. «Генеральная репетиция на новом сервере» — прогнана на реальном железе (Poincare).** Отдельный compose-проект, пустой том, весь `backend/data/sql` смонтирован в `initdb.d`: ``` готов на итерации 2 status=running exit=0 ошибок в логе: 0 таблиц 73, индексов 250, невалидных 0 NOTICE: 077: USER MAPPING для gendesign_remote нет — backfill пропущен database system is ready to accept connections ``` Тестовый контейнер и том удалены после прогона. **4. «Проверка невалидных индексов перенесена из деплоя в CI» — PR #3150.** Продублирована, не перенесена — обоснование в описании PR: CI собирает схему с нуля и по построению не воспроизводит оборванный CIC на живой базе, так что снятие проверки из деплоя было бы регрессией #2752. Оба пути гейта прогнаны на реальной базе. Закрываю после мержа #3150.
Collaborator

PR #3150 смержен. Гейт отработал в самом прогоне CI:

✓ схема собрана: 73 таблиц
✓ невалидных индексов нет

Все четыре пункта acceptance закрыты (п.1 и п.2 — эквивалентным решением, обоснование в комментарии выше). Закрываю.

PR #3150 смержен. Гейт отработал в самом прогоне CI: ``` ✓ схема собрана: 73 таблиц ✓ невалидных индексов нет ``` Все четыре пункта acceptance закрыты (п.1 и п.2 — эквивалентным решением, обоснование в комментарии выше). Закрываю.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2990
No description provided.