Промоут новой версии продукта и rolling update
Как продвинуть новую версию в is_current, как enqueue'ить апдейт на все стейл-тенанты, как откатиться при сбое.
У продукта может быть много версий, но только одна с is_current = true. Эта версия достаётся новым клиентам при заказе тенанта; для существующих клиентов она триггерит rolling update.
Пайплайн обновления — backup → migrate → smoke → switch с авто-rollback на любом шаге. Реализация в api/internal/versions/updater.go.
Регистрация версии
После того как CI продукта собрал и запушил образ в наш registry (registry.wl-solution.com), оператор делает POST /admin/products/<id>/versions с {version, git_ref, artifact_image, is_breaking, migration_required, release_notes}.
Все поля идут в таблицу product_versions. На этом этапе ничего ни с кем не происходит — просто запись в каталоге.
Promote — пометка as current
POST /admin/products/<id>/versions/<version>/promote в транзакции сбрасывает is_current у предыдущей текущей и проставляет у новой. С этой секунды новые тенанты будут получать новую версию.
Существующие тенанты автоматически НЕ обновляются — это сознательное решение: мы хотим, чтобы оператор сам решил, когда катить rollout (например, после ночного бэкапа).
Rollout — раздача апдейта
POST /admin/products/<id>/rollout. Контроллер находит все deployments этого продукта со старой версией и для каждого ставит в jobs запись с kind = deploy.update и payload {deployment_id, target_version}.
Worker (api/cmd/worker) подхватывает их по одной — мы не катим параллельно, чтобы не положить registry под нагрузкой image-pull'ов.
Пайплайн на одном тенанте: backup → migrate → smoke → switch
1. backup: pg_dump базы тенанта в /opt/backups/<deployment_id>/<timestamp>.sql.gz
2. migrate: docker exec на старом контейнере с MIGRATE=up — миграции запускаются ДО переключения трафика, на старом коде. Если миграция падает — откатываем БД на бэкап и job завершается с ошибкой.
3. smoke: запускаем новый контейнер на параллельном порту, делаем 10 HTTP-проб /health. Если не зелёный — убиваем новый контейнер, оставляем старый.
4. switch: Caddy reload на нового апстрима. Старый контейнер удерживается ещё минуту, потом удаляется (graceful drain).
Если что-то пошло не так
OnFailure хук jobs-раннера шлёт алерт в Telegram + Sentry, если obs.* настроено. Конкретный шаг видно в deployment_events. БД остаётся в состоянии до начала миграции — бэкап лежит в /opt/backups.
Восстановление вручную: psql < /opt/backups/<id>/<ts>.sql.gz, docker compose up старой версии, далее /admin/deployments/<id>/update на новую версию когда фикс готов.
- 1POST /admin/products/<id>/versionsЗарегистрировать новую версию с тегом образа в registry.
- 2POST /admin/products/<id>/versions/<v>/promoteПометить is_current — новые клиенты получат её сразу.
- 3GET /admin/products/<id>/staleПосмотреть список тенантов на старой версии.
- 4POST /admin/products/<id>/rolloutEnqueue апдейтов на все stale-тенанты. Прогресс в /admin/jobs.
Хотите развернуть свой тенант на wl-installer?
Аренда: 5 минут от заказа до боевого URL. Покупка с исходниками: 1–5 рабочих дней.