gendesign/backend/tests/ops/test_2950_deploy_concurrency_group.py
bot-backend 2a01dea103
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy Trade-In / changes (push) Successful in 10s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-worker (push) Successful in 51s
Deploy / build-backend (push) Successful in 52s
Deploy / build-frontend (push) Successful in 51s
Deploy Trade-In / build-browser (push) Successful in 32s
Deploy / deploy (push) Successful in 1m21s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Successful in 3m30s
Deploy Trade-In / test (push) Successful in 4m15s
Deploy Trade-In / build-backend (push) Successful in 31s
Deploy Trade-In / deploy (push) Successful in 2m6s
Deploy Trade-In / deploy-status (push) Successful in 2s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
fix(ci): прод-деплои в одну группу concurrency — прун одного убивал pull другого (#2950) (#2952)
2026-08-20 07:47:48 +00:00

62 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Гейт: оба прод-деплоя обязаны лежать в ОДНОЙ группе concurrency.
Почему это тест, а не комментарий в yml (#2950). Деплой ПТИЦЫ и деплой Trade-In
ходят по SSH в один и тот же докер-демон — стеки gendesign-* и tradein-* плюс сам
forgejo-runner живут на одной VM. Каждый в конце делает `docker image prune -af`.
Пока группы разные, Forgejo запускает их параллельно, и прун одного сносит leases
ещё не доехавшего `compose pull` другого:
unable to lease content: lease does not exist: not found
20.08 так и вышло: run 8083 упал за 5 секунд, прод остался на старом коде. Разводка
групп обратно ничего не сломает в CI и не даст ни одного сигнала — отказ проявится
только в следующем совпадении окон двух мержей. Поэтому инвариант зафиксирован здесь.
`cancel-in-progress: false` частью инварианта тоже является: прод-деплои обязаны
достаиваться в очереди, а не отменять друг друга — отменённый деплой оставляет прод
на старом коде ровно так же, как упавший.
"""
from pathlib import Path
import pytest
import yaml
# backend/tests/ops/<этот файл> → корень репозитория
REPO_ROOT = Path(__file__).resolve().parents[3]
WORKFLOWS = REPO_ROOT / ".forgejo" / "workflows"
PROD_DEPLOYS = ("deploy.yml", "deploy-tradein.yml")
def _concurrency(name: str) -> dict:
path = WORKFLOWS / name
assert path.is_file(), f"нет {path} — переехал workflow, гейт ослеп"
return yaml.safe_load(path.read_text()).get("concurrency") or {}
@pytest.mark.parametrize("name", PROD_DEPLOYS)
def test_prod_deploy_declares_concurrency(name: str) -> None:
"""У каждого прод-деплоя concurrency вообще объявлена."""
assert _concurrency(name).get(
"group"
), f"{name}: пропала секция concurrency — деплои снова могут пойти параллельно"
def test_both_prod_deploys_share_one_group() -> None:
"""Группа у обоих одна и та же — иначе прун одного убьёт pull другого."""
groups = {name: _concurrency(name).get("group") for name in PROD_DEPLOYS}
assert len(set(groups.values())) == 1, (
f"прод-деплои разведены по разным группам concurrency: {groups}. "
"Они ходят в ОДИН докер-демон; `docker image prune -af` одного обрывает "
"`compose pull` другого (#2950)."
)
@pytest.mark.parametrize("name", PROD_DEPLOYS)
def test_prod_deploy_queues_instead_of_cancelling(name: str) -> None:
"""Раны достаиваются в очереди: отменённый деплой = прод на старом коде."""
assert _concurrency(name).get("cancel-in-progress") is False, (
f"{name}: cancel-in-progress должен быть false — иначе более новый мерж "
"отменит выкатку предыдущего и та молча не доедет"
)