Files
mdm-ordinis/docs-internal/ops/db-migrations.md
T
Zimin A.N. bcfb07f547 docs: split integrator guide (Diplodoc) vs internal docs + add build-docs CI
Чёткое разделение audiences:
- docs/ — consumer-facing only, Diplodoc-built. Public contract для
  интеграторов (Альтум, BI, third-party).
- docs-internal/ — operator runbooks, status snapshots, legacy tech pages.
  НЕ в Diplodoc build, НЕ публикуются.

Изменения:
- Move docs/{ops,status,tech} → docs-internal/{ops,status,tech}
- docs/toc.yaml: убраны секции Operations, Архитектура (legacy), Status
- docs/index.md: убран tab "оператор / on-call", focus на integrators
- docs/README.md: rewritten — scope только integrator guide, editorial
  guidelines (no leak internal architecture, stable API contract)
- .yfm: убран явный ignore status/* (теперь не нужно — папка переехала)
- docs-internal/README.md: index для внутренней документации с rationale
  разделения

Scrubbing implementation details из Diplodoc страниц:
- events.md: убраны Strimzi/cluster.142 references, OutboxPoller детали,
  internal alert names (OrdinisOutboxLagHigh, OrdinisOutboxDLQNonEmpty),
  metric names (nsi_outbox_*). Заменены на consumer-observable contract.
- webhooks.md: убраны metric names (nsi_webhook_ssrf_rejected_total),
  alert table (OrdinisWebhookHighFailureRate и т.д.). Retry policy
  переписана на user-side perspective.
- errors.md: убран alert name OrdinisReadApiErrorBudgetBurnFast, Tempo
  endpoint URL, internal connection details.
- x-references.md: OrphanReferenceScanner → general "Ordinis периодически
  детектирует". Убраны metric/alert names. Cascade roadmap без link на
  internal design doc.
- auth.md: убран file path ScopeContext.java.
- bundle-cuod.md: убран Maven module path.
- caching.md: cascade design link заменён на text reference.

CI:
- .gitlab-ci.yml: новый job build-docs (stage: build) — Node 20 alpine,
  pnpm install --frozen-lockfile + pnpm build, artifact docs/_dist на
  неделю. Triggers: auto на docs/**, либо manual web. Готов к follow-up
  pages-deploy job когда host решён.
- Новый pattern .docs-changes для rules.

Build verified clean: 13 HTML pages, 6.9M, no broken links/refs.
2026-05-07 23:27:03 +03:00

6.2 KiB
Raw Blame History

Runbook: Liquibase миграции БД

Источник правды: ordinis-migrations/src/main/resources/db/changelog/

  • master.xml — список включённых changelog'ов в порядке применения.
  • changes/00NN-*.xml — конкретные изменения (CREATE TABLE, ADD COLUMN и т.д.).

Миграции применяются автоматически при старте ordinis-app через spring.liquibase (Spring Boot starter). Если миграция падает — pod не стартует, остальные pods тоже не поднимутся (read-api/projection-writer имеют startup-зависимость от схемы БД).

1. Просмотр applied миграций

export KUBECONFIG=/tmp/kubeconfig-161
PG_PASS=$(kubectl get secret -n ordinis-staging ordinis-postgres-app \
  -o jsonpath='{.data.password}' | base64 -d)
kubectl exec -n ordinis-staging ordinis-postgres-1 -c postgres -- \
  env PGPASSWORD="$PG_PASS" psql -h localhost -U ordinis_app -d ordinis -c \
  "SELECT id, author, dateexecuted, exectype FROM databasechangelog ORDER BY orderexecuted;"

Колонка exectype:

  • EXECUTED — миграция применена успешно
  • FAILED — упала (pod не должен стартовать в этом случае)
  • MARK_RAN — пропущена через preCondition
  • RERAN — была применена повторно (manual)

2. Добавление новой миграции

  1. Создать ordinis-migrations/src/main/resources/db/changelog/changes/00NN-<topic>.xml.
    • Номер строго следующий (последний +1).
    • Author = ordinis.
    • Idempotent: использовать <preConditions onFail="MARK_RAN"> для добавлений.
  2. Зарегистрировать в master.xml через <include file="changes/00NN-*.xml"/>.
  3. Тестировать локально на dev-Postgres:
    docker run -d --rm --name ord-pg -e POSTGRES_PASSWORD=dev \
      -p 5432:5432 postgres:18
    mvn -pl ordinis-migrations -am liquibase:update \
      -Dliquibase.url=jdbc:postgresql://localhost:5432/postgres \
      -Dliquibase.username=postgres -Dliquibase.password=dev
    
  4. Commit + push. CI пересобирает app image, deploy применяет новые миграции при следующем старте pod'а.

3. Откат миграции

⚠️ Liquibase rollback требует <rollback> блок в changeset. Без него автоматический откат невозможен — только manual SQL.

Если changeset имеет <rollback>

# Через kubectl exec на pod где есть mvn — обычно нет, проще локально:
mvn -pl ordinis-migrations -am liquibase:rollback \
  -Dliquibase.url=jdbc:postgresql://192.168.100.161:5432/ordinis \
  -Dliquibase.username=ordinis_app \
  -Dliquibase.password=$PG_PASS \
  -Dliquibase.rollbackCount=1

Manual SQL (если rollback не задан)

  1. Прочитать changeset XML — посмотреть какие изменения сделаны.
  2. Написать обратные SQL (DROP TABLE, ALTER TABLE DROP COLUMN и т.д.).
  3. Удалить запись из databasechangelog:
    DELETE FROM databasechangelog WHERE id = '00NN-1-some-id' AND author = 'ordinis';
    
  4. После этого Liquibase при следующем старте либо переприменит миграцию (если она всё ещё в master.xml), либо считает её не-применённой.

4. Failed migration recovery

Сценарий: миграция упала, pod в CrashLoopBackOff.

A) Миграция частично применилась

Liquibase помечает changeset как FAILED в databasechangelog. Чтобы повторить:

DELETE FROM databasechangelog WHERE id = '00NN-1-broken' AND exectype = 'FAILED';

После этого pod рестарт → Liquibase снова попытается. Если миграция всё ещё broken, исправить XML (или применённый частично state в БД), пересобрать image, redeploy.

B) Миграция полностью применилась но с ошибкой в данных

Например column добавлена с NOT NULL без default. Manual SQL:

ALTER TABLE my_table ALTER COLUMN broken_col DROP NOT NULL;
-- либо UPDATE my_table SET broken_col = 'default' WHERE broken_col IS NULL;

И исправить XML на defaultValueComputed=... для следующих deployments.

5. Текущий список миграций (на 2026-05-05)

ID Назначение
0001-extensions.xml PostGIS, btree_gist (для tstzrange exclusion)
0002-dictionary-definitions.xml Таблица dictionary_definitions
0003-dictionary-records.xml Таблица dictionary_records + tstzrange exclusion
0004-audit-log.xml Таблица audit_log
0005-outbox-events.xml Таблица outbox_events + partial index
0006-idempotency-keys.xml Таблица idempotency_keys
0007-add-version-columns.xml JPA optimistic lock columns
0008-fix-scope-check-uppercase.xml Чек на scope в верхнем регистре
0009-fix-records-scope-check.xml Чек consistency dictionary↔record scope
0010-envers-tables.xml Hibernate Envers (revinfo, *_aud)
0011-outbox-dlq.xml DLQ column + partial indexes

6. Эскалация

Проблема Действие
Migration на staging упала, pod не стартует DELETE FAILED row + fix XML + redeploy. См. §4A.
Migration on prod упала СТОП. Не делать manual fix без apply tech lead. Возможно нужен rollback всего deployment.
databasechangelog lock застрял (другая миграция параллельно) DELETE FROM databasechangelog_lock WHERE id=1; INSERT INTO databasechangelog_lock VALUES (1, false, NULL, NULL);
Postgres недоступен См. CNPG cluster status: kubectl get cluster -n ordinis-staging