feat(deploy): healthcheck api и worker, отдельный migrate-сервис, лимит загрузки отчёта

Миграции вынесены из команды api в one-shot сервис migrate, api и worker стартуют после него. /health отвечает 503 при недоступной БД. Отчёт больше MAX_UPLOAD_BYTES (25 МиБ) получает 413, Caddy режет на 30 МБ раньше. Том uploads убран, секреты env_file передаются сервисам явно. В CI добавлена сборка образа бэкенда без push, test_migrations сверяет модели с историей Alembic.
This commit is contained in:
Dmitry
2026-09-19 21:55:33 +03:00
parent 600496048f
commit 4a0b4e0532
11 changed files with 139 additions and 21 deletions
+9 -2
View File
@@ -4,13 +4,19 @@
```bash
cp .env.example .env # заполнить POSTGRES_PASSWORD, JWT_SECRET (openssl rand -hex 32), DOMAIN, токены
just up # docker compose up -d --build: db, api (миграции при старте), worker, caddy, pg-backup
just up # docker compose up -d --build: db, migrate (one-shot `alembic upgrade head`), api, worker, caddy, pg-backup
docker compose exec api fintracker create-user you@example.com
```
- Caddy: авто-TLS на `DOMAIN`, `/api/*` → api:8000, остальное — Flutter web из `app/build/web`.
- Worker — единственный экземпляр планировщика; ручной синк через `POST /api/v1/sync/{source}`
ставит задачу в `sync_job`, worker забирает её раз в 5 с.
- Расписание — `worker/jobs.default_schedule()`: zenmoney каждые 30 мин, cbr 13:45 и 18:00 МСК,
tinvest каждые 3 ч с 8:10, moex в 10:20/14:20/19:20/23:20, tinvest_events и moex_payouts раз в
сутки утром. tinvest* без `TINVEST_TOKEN` в расписание не берутся (в логе worker'а — warning).
- Healthcheck: `api` ходит на `/api/v1/health` (503, если БД недоступна), `worker` пишет файл
`/tmp/fintracker-worker-heartbeat` каждые 10 с, проверка смотрит на его возраст (< 60 с).
Compose сам не перезапускает unhealthy-контейнер — статус виден в `docker compose ps`.
- `pg-backup` делает `pg_dump -Fc` раз в сутки в `./backups`, хранит 14 дней; off-site копию
настраивает хост (rclone/cron), см. открытый вопрос в плане.
@@ -26,6 +32,7 @@ docker compose up -d
## Секреты
Только `.env` на сервере. В чат и в git не попадают. T-Invest токен — read-only.
В compose секреты раздаются по потребности: `api`/`worker` читают весь `.env`, `migrate` получает только `DATABASE_URL`, `db` и `pg-backup``POSTGRES_*`, `caddy``DOMAIN`.
## Проверено с podman (2026-09-17)
@@ -33,4 +40,4 @@ docker compose up -d
- Имена образов в `docker-compose.yml` и `Dockerfile` полностью квалифицированы (`docker.io/library/...`) — podman без `unqualified-search-registries` короткие имена не резолвит.
- **Прокси хоста впекается в образ** при `podman build`/`compose --build` (`HTTP_PROXY` попадает в `Config.Env`), после чего запросы к `localhost` внутри контейнера идут в недостижимый прокси. Поэтому `just up` собирает с `env -u …proxy…`. На VPS без прокси это ни на что не влияет.
- `env_file: .env` в compose — буквальный путь; `--env-file` меняет только подстановку `${…}` в самом compose-файле.
- Команда `api` использует `exec`, иначе `sh -c` не передаёт SIGTERM uvicorn'у и compose добивает контейнер по таймауту.
- Миграции идут в one-shot сервисе `migrate`; `api` и `worker` ждут его `service_completed_successfully`. Для podman-compose это условие не проверялось.