fix(ci): деплой падает громко, если :latest отстаёт от головы по компоненту (#2950) #3023

Merged
bot-backend merged 2 commits from fix/2950-latest-revision-gate into main 2026-08-21 12:19:08 +00:00
Collaborator

Что случилось 21.08 (хронология из статусов run'ов)

  • 10:27 push ccf84b4a (#3018, backend+frontend) → run 8326: build-backend ✓ 10:30:10, build-worker ✓ 10:34:08, build-frontend ✓ 10:34:14, deploy — «Has been cancelled» 10:35:13.
  • 10:35:09 push 95db3f44 (#3019, ops-only) → run 8329 стартовал 10:35:12, билды skipped, deploy ✓ 10:37:05 — накатил :latest как есть.
  • Прод оказался на новом коде только потому, что образы ccf84b4a легли за 70 с до pull'а. При обратном порядке голова main была бы зелёной, а прод — на старом образе, и это не заметил бы никто (проверял по коду в контейнерах).

cancel-in-progress: false объявлен, но на ещё не стартовавший job Forgejo 10.0.3 его не применяет. Host-lock (#2955) закрывает гонку прунов, эту дыру — нет.

Что делает PR

  • docker/build-push-action: labels: org.opencontainers.image.revision=${{ github.sha }} на всех 12 шагах (попытка + ретрай × backend/worker/frontend и tradein backend/frontend/browser).
  • scripts/check-latest-image-revision.sh <image> <timeout> -- <paths…>: читает ревизию :latest из registry (imagetools inspect), требует, чтобы она содержала последний коммит по путям компонента (git log -1 -- paths на checkout'е run'а; пути = фильтры changes, которые запускают сборку), ждёт билд предшественника до 15 мин и иначе ::error + exit 1. Ревизия новее — ок (dispatch собирает голову).
  • Шаги в deploy-job обоих workflow перед SSH: checkout (fetch-depth 0), login GHCR, гард по каждому образу.

Test plan

  • backend/tests/test_2950_latest_image_revision_gate.py (подменный docker на PATH + настоящий временный git): свежий → 0; ревизия новее → 0; отстаёт → ждёт, затем 1 с ::error; чужой компонент → 1; без метки → 1; registry упал → 1; usage → 2. Мутация «скрипт всегда 0» → 5/7 красных. Три прогона подряд зелёные.
  • YAML обоих workflow валиден; check-workflow-ports.py ✓; существующий test_2950_deploy_concurrency_group.py зелёный.
  • Первый прогон после мержа соберёт все образы с меткой (workflow-файлы в infra), гард в том же run'е должен пройти — это живая проверка формата imagetools inspect --format '{{json .Image}}' на наших образах.
  • Дальше: два мержа подряд (код + ops-only) — второй run ждёт билд первого и проходит; если билд первого упал — второй падает с понятным ::error.

⚠️ Первый деплой после этого PR может ждать до 15 мин, если параллельно идёт чужой билд — это ожидаемо.

Refs #2950

## Что случилось 21.08 (хронология из статусов run'ов) - 10:27 push `ccf84b4a` (#3018, backend+frontend) → run 8326: build-backend ✓ 10:30:10, build-worker ✓ 10:34:08, build-frontend ✓ 10:34:14, **deploy — «Has been cancelled» 10:35:13**. - 10:35:09 push `95db3f44` (#3019, ops-only) → run 8329 стартовал 10:35:12, билды **skipped**, `deploy` ✓ 10:37:05 — накатил `:latest` как есть. - Прод оказался на новом коде только потому, что образы `ccf84b4a` легли за **70 с** до pull'а. При обратном порядке голова main была бы зелёной, а прод — на старом образе, и это не заметил бы никто (проверял по коду в контейнерах). `cancel-in-progress: false` объявлен, но на ещё не стартовавший job Forgejo 10.0.3 его не применяет. Host-lock (#2955) закрывает гонку прунов, эту дыру — нет. ## Что делает PR - `docker/build-push-action`: `labels: org.opencontainers.image.revision=${{ github.sha }}` на всех 12 шагах (попытка + ретрай × backend/worker/frontend и tradein backend/frontend/browser). - `scripts/check-latest-image-revision.sh <image> <timeout> -- <paths…>`: читает ревизию `:latest` из registry (`imagetools inspect`), требует, чтобы она **содержала** последний коммит по путям компонента (`git log -1 -- paths` на checkout'е run'а; пути = фильтры `changes`, которые запускают сборку), ждёт билд предшественника до 15 мин и иначе `::error` + exit 1. Ревизия новее — ок (dispatch собирает голову). - Шаги в `deploy`-job обоих workflow перед SSH: checkout (fetch-depth 0), login GHCR, гард по каждому образу. ## Test plan - [x] `backend/tests/test_2950_latest_image_revision_gate.py` (подменный `docker` на PATH + настоящий временный git): свежий → 0; ревизия новее → 0; отстаёт → ждёт, затем 1 с `::error`; чужой компонент → 1; без метки → 1; registry упал → 1; usage → 2. Мутация «скрипт всегда 0» → 5/7 красных. Три прогона подряд зелёные. - [x] YAML обоих workflow валиден; `check-workflow-ports.py` ✓; существующий `test_2950_deploy_concurrency_group.py` зелёный. - [ ] Первый прогон после мержа соберёт все образы с меткой (workflow-файлы в `infra`), гард в том же run'е должен пройти — это живая проверка формата `imagetools inspect --format '{{json .Image}}'` на наших образах. - [ ] Дальше: два мержа подряд (код + ops-only) — второй run ждёт билд первого и проходит; если билд первого упал — второй падает с понятным `::error`. ⚠️ Первый деплой после этого PR может ждать до 15 мин, если параллельно идёт чужой билд — это ожидаемо. Refs #2950
bot-backend added 1 commit 2026-08-21 11:50:42 +00:00
fix(ci): деплой падает громко, если :latest отстаёт от головы по компоненту (#2950)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m7s
CI / backend-tests (pull_request) Successful in 17m41s
54889a956b
Почему: деплой катит IMAGE_TAG=latest. Forgejo отменяет ещё не стартовавший
deploy предыдущего run'а той же группы при новом push (cancel-in-progress:
false на pending-job не действует): 21.08 10:35:13 deploy run'а ccf84b4a
«Has been cancelled» через 4 с после старта run'а 95db3f44 (ops-only, билды
пропущены), и тот накатил :latest как есть. Прод получил новый код только
потому, что билды ccf84b4a легли в 10:34:08/14 — за 70 с до pull'а; иначе
голова была бы зелёной, а прод — на старом образе. Host-lock (#2955)
закрывает гонку прунов, но не эту.

Что: build-push-action ставит org.opencontainers.image.revision=github.sha
(12 шагов: попытка+ретрай × 6 образов). В deploy-job обоих workflow перед
SSH — scripts/check-latest-image-revision.sh: читает ревизию :latest из
registry (imagetools inspect), требует, чтобы она содержала последний
коммит по путям компонента (те же фильтры, что запускают сборку), ждёт билд
предшественника до 15 мин, иначе ::error и выход 1. Ревизия новее — ок
(workflow_dispatch собирает голову).

Тест test_2950_latest_image_revision_gate.py: подменный docker на PATH +
настоящий временный git; коды выхода по значению (свежий 0, новее 0, отстаёт
1 с ожиданием, чужой компонент 1, без метки 1, registry упал 1, usage 2);
мутация «всегда 0» → 5/7 красных.

Refs #2950
Light1YT added 1 commit 2026-08-21 11:52:13 +00:00
test(ci): гард #2950 — дедлайн теста ожидания 3 с вместо 1 (секундная гранулярность date +%s давала флейк 2 из 3)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m9s
CI / backend-tests (pull_request) Successful in 17m49s
4d9d03cb07
bot-backend merged commit f2945b7157 into main 2026-08-21 12:19:08 +00:00
bot-backend deleted branch fix/2950-latest-revision-gate 2026-08-21 12:19:08 +00:00
Sign in to join this conversation.
No reviewers
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#3023
No description provided.