refactor: separate migrations from API runtime
This commit is contained in:
@@ -44,6 +44,8 @@ RF4DB/RF4-STAT/RF4MAP/RF4 Posts сначала принимаются в изо
|
|||||||
|
|
||||||
В production MinIO root credentials доступны только одноразовому init-контейнеру. API использует отдельного пользователя с доступом исключительно к `S3_BUCKET`: просмотр bucket, чтение, запись и удаление его объектов без глобального списка bucket и без права создавать новые.
|
В production MinIO root credentials доступны только одноразовому init-контейнеру. API использует отдельного пользователя с доступом исключительно к `S3_BUCKET`: просмотр bucket, чтение, запись и удаление его объектов без глобального списка bucket и без права создавать новые.
|
||||||
|
|
||||||
|
Production release отделяет Alembic от runtime: одноразовый `migrate` должен успешно завершиться до запуска новой версии API. Перед изменением схемы создаётся backup; совместимый rollback возвращает предыдущие images, несовместимый — восстанавливает предрелизную копию данных вместо непроверенного `alembic downgrade`.
|
||||||
|
|
||||||
После повторных ошибок scheduler увеличивает паузу экспоненциально до 24 часов и возвращается к 30 минутам после успеха. Публичная страница `/status` показывает свежесть и состояние источников без URL запросов, внутренних ошибок и другой диагностической информации.
|
После повторных ошибок scheduler увеличивает паузу экспоненциально до 24 часов и возвращается к 30 минутам после успеха. Публичная страница `/status` показывает свежесть и состояние источников без URL запросов, внутренних ошибок и другой диагностической информации.
|
||||||
|
|
||||||
Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md).
|
Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md).
|
||||||
|
|||||||
+1
-1
@@ -8,4 +8,4 @@ COPY --chown=rf4:rf4 apps/api .
|
|||||||
COPY --chown=rf4:rf4 rf4_research ./rf4_research
|
COPY --chown=rf4:rf4 rf4_research ./rf4_research
|
||||||
USER rf4
|
USER rf4
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
CMD ["sh", "-c", "alembic upgrade head && python -m app.seed && uvicorn app.main:app --host 0.0.0.0 --port 8000 --no-access-log"]
|
CMD ["sh", "-c", "python -m app.seed && uvicorn app.main:app --host 0.0.0.0 --port 8000 --no-access-log"]
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ services:
|
|||||||
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
||||||
depends_on:
|
depends_on:
|
||||||
db: {condition: service_healthy}
|
db: {condition: service_healthy}
|
||||||
|
migrate: {condition: service_completed_successfully}
|
||||||
minio: {condition: service_healthy}
|
minio: {condition: service_healthy}
|
||||||
minio-init: {condition: service_completed_successfully}
|
minio-init: {condition: service_completed_successfully}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -155,6 +156,23 @@ services:
|
|||||||
resources:
|
resources:
|
||||||
limits: {cpus: "1.00", memory: 1G}
|
limits: {cpus: "1.00", memory: 1G}
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: apps/api/Dockerfile
|
||||||
|
restart: "no"
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: ${DATABASE_URL:?Set DATABASE_URL}
|
||||||
|
depends_on:
|
||||||
|
db: {condition: service_healthy}
|
||||||
|
command: ["alembic", "upgrade", "head"]
|
||||||
|
networks: [backend]
|
||||||
|
security_opt: [no-new-privileges:true]
|
||||||
|
logging: *default-logging
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits: {cpus: "0.50", memory: 256M}
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build:
|
build:
|
||||||
context: ./apps/web
|
context: ./apps/web
|
||||||
|
|||||||
+15
-1
@@ -51,6 +51,8 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
migrate:
|
||||||
|
condition: service_completed_successfully
|
||||||
minio:
|
minio:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
@@ -61,6 +63,18 @@ services:
|
|||||||
timeout: 3s
|
timeout: 3s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: apps/api/Dockerfile
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql+psycopg://rf4:rf4_local@db:5432/rf4_spotter
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
command: ["alembic", "upgrade", "head"]
|
||||||
|
restart: "no"
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: ./apps/web
|
build: ./apps/web
|
||||||
environment:
|
environment:
|
||||||
@@ -87,7 +101,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
command: ["sh", "-c", "alembic upgrade head && python -m app.cli import-records"]
|
command: ["python", "-m", "app.cli", "import-records"]
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
build:
|
build:
|
||||||
|
|||||||
+7
-4
@@ -38,7 +38,8 @@ docker run --rm caddy:2.10.2-alpine caddy hash-password --plaintext 'ОТДЕЛ
|
|||||||
```bash
|
```bash
|
||||||
docker compose --env-file .env.production -f compose.production.yaml config --quiet
|
docker compose --env-file .env.production -f compose.production.yaml config --quiet
|
||||||
docker compose --env-file .env.production -f compose.production.yaml build
|
docker compose --env-file .env.production -f compose.production.yaml build
|
||||||
docker compose --env-file .env.production -f compose.production.yaml up -d
|
docker compose --env-file .env.production -f compose.production.yaml run --rm migrate
|
||||||
|
docker compose --env-file .env.production -f compose.production.yaml up -d --no-deps api web community-scheduler
|
||||||
docker compose --env-file .env.production -f compose.production.yaml ps
|
docker compose --env-file .env.production -f compose.production.yaml ps
|
||||||
curl -fsS https://rf4spotter.ru/health
|
curl -fsS https://rf4spotter.ru/health
|
||||||
curl -fsS https://rf4spotter.ru/ready
|
curl -fsS https://rf4spotter.ru/ready
|
||||||
@@ -64,7 +65,7 @@ curl -fsS -H "Authorization: Bearer $ADMIN_TOKEN" -o rf4spotter-diagnostics.json
|
|||||||
|
|
||||||
По умолчанию временно используются только loopback-порты `14321` и `18000`; PostgreSQL и MinIO наружу не публикуются. Контур и volumes удаляются после проверки. Drill успешно пройден 6 сентября 2026 года.
|
По умолчанию временно используются только loopback-порты `14321` и `18000`; PostgreSQL и MinIO наружу не публикуются. Контур и volumes удаляются после проверки. Drill успешно пройден 6 сентября 2026 года.
|
||||||
|
|
||||||
API-контейнер перед стартом применяет Alembic-миграции и запускает идемпотентный seed. В production он добавляет только минимальные справочники и точки; демонстрационные уловы жёстко отключены настройкой `SEED_DEMO_DATA=false`.
|
Одноразовый `migrate` применяет Alembic до rollout API; при ошибке новый runtime не запускается. API при старте выполняет только идемпотентный seed: в production он добавляет минимальные справочники и точки, а демонстрационные уловы жёстко отключены `SEED_DEMO_DATA=false`.
|
||||||
|
|
||||||
Проверка TLS и маршрутизации:
|
Проверка TLS и маршрутизации:
|
||||||
|
|
||||||
@@ -92,12 +93,14 @@ docker compose --env-file .env.production -f compose.production.yaml exec api py
|
|||||||
```bash
|
```bash
|
||||||
git pull --ff-only
|
git pull --ff-only
|
||||||
docker compose --env-file .env.production -f compose.production.yaml build
|
docker compose --env-file .env.production -f compose.production.yaml build
|
||||||
docker compose --env-file .env.production -f compose.production.yaml up -d
|
./deploy/backup.sh /srv/rf4-backups
|
||||||
|
docker compose --env-file .env.production -f compose.production.yaml run --rm migrate
|
||||||
|
docker compose --env-file .env.production -f compose.production.yaml up -d --no-deps api web community-scheduler
|
||||||
docker compose --env-file .env.production -f compose.production.yaml ps
|
docker compose --env-file .env.production -f compose.production.yaml ps
|
||||||
curl -fsS https://rf4spotter.ru/ready
|
curl -fsS https://rf4spotter.ru/ready
|
||||||
```
|
```
|
||||||
|
|
||||||
Перед обновлением со сменой схемы обязателен backup PostgreSQL. Не удаляйте volumes и не используйте `down -v`.
|
Перед обновлением со сменой схемы обязателен backup PostgreSQL. Если миграция не началась или схема обратно совместима, верните предыдущий Git commit/images и повторите rollout без downgrade Alembic. Если миграция изменила данные несовместимо, остановите API/web и восстановите сделанный перед release backup через `restore.sh`, затем запустите предыдущую ревизию. Не удаляйте volumes, не используйте `down -v` и не выполняйте `alembic downgrade` без отдельно проверенного плана конкретной миграции.
|
||||||
|
|
||||||
## 6. Резервное копирование и восстановление
|
## 6. Резервное копирование и восстановление
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@
|
|||||||
- [x] **Q06 · Performance baseline.** На локальной production-сборке после оптимизации hero: performance 100, LCP 1,66 с, FCP 1,15 с, CLS 0,023, TBT 9 мс. Устранены найденные Lighthouse проблемы контраста и accessible name; методика и бюджеты записаны в [performance-baseline.md](performance-baseline.md). Полевой INP измеряется только после запуска.
|
- [x] **Q06 · Performance baseline.** На локальной production-сборке после оптимизации hero: performance 100, LCP 1,66 с, FCP 1,15 с, CLS 0,023, TBT 9 мс. Устранены найденные Lighthouse проблемы контраста и accessible name; методика и бюджеты записаны в [performance-baseline.md](performance-baseline.md). Полевой INP измеряется только после запуска.
|
||||||
- [x] **Q07 · Нагрузочная методика.** Добавлен read-only runner для activity, records, staging и moderation с warm-up, p50/p95/max, распределением HTTP-кодов и ограниченной concurrency. Методика фиксирует контекст запуска, ступени нагрузки и бюджеты, но не объявляет результатов до трёх прогонов на целевом сервере.
|
- [x] **Q07 · Нагрузочная методика.** Добавлен read-only runner для activity, records, staging и moderation с warm-up, p50/p95/max, распределением HTTP-кодов и ограниченной concurrency. Методика фиксирует контекст запуска, ступени нагрузки и бюджеты, но не объявляет результатов до трёх прогонов на целевом сервере.
|
||||||
- [x] **Q08 · Политика MinIO.** Production bootstrap создаёт bucket и отдельную policy только с bucket location/list и get/put/delete его объектов. App credentials проверяются через bucket stat и отрицательную проверку глобального list; API больше не требует `ListAllMyBuckets` и не пытается создавать bucket. Root credentials остаются только у init-задачи.
|
- [x] **Q08 · Политика MinIO.** Production bootstrap создаёт bucket и отдельную policy только с bucket location/list и get/put/delete его объектов. App credentials проверяются через bucket stat и отрицательную проверку глобального list; API больше не требует `ListAllMyBuckets` и не пытается создавать bucket. Root credentials остаются только у init-задачи.
|
||||||
- [ ] **Q09 · Release-процедура.** Разделить миграционный/release-шаг и запуск приложения либо документировать выбранную стратегию отката; проверить upgrade с предыдущей ревизии на копии данных.
|
- [ ] **Q09 · Release-процедура — код готов.** Миграции вынесены из API runtime в одноразовый `migrate` service; API запускается только после успешного Alembic upgrade. Документированы backup, rollout и два варианта отката. Осталось проверить upgrade с предыдущей ревизии на копии данных в изолированном Compose drill.
|
||||||
- [ ] **Q10 · Документальная ревизия.** После каждого пакета обновлять этот файл и README, не возвращая закрытые R/A/T-задачи в активный backlog.
|
- [ ] **Q10 · Документальная ревизия.** После каждого пакета обновлять этот файл и README, не возвращая закрытые R/A/T-задачи в активный backlog.
|
||||||
|
|
||||||
### Дополнения после ревизии PROJECT_AUDIT_2026-09-10
|
### Дополнения после ревизии PROJECT_AUDIT_2026-09-10
|
||||||
|
|||||||
Reference in New Issue
Block a user