ci: смоук периметра МЕРЫ запускается сразу после деплоя (#2917) #2922

Merged
bot-backend merged 1 commit from ci/2917-perimeter-smoke-after-deploy into main 2026-08-19 08:13:50 +00:00
Collaborator

Что было

scripts/smoke-mera-perimeter.sh — единственная проверка, которая видит публичный периметр
целиком: короткие адреса, 301 с длинных, публичный API, закрытость B2B-путей на публичном
домене. Запускался он только по workflow_dispatch и ночному cron'у 17 6 * * *.

Ни deploy.yml, ни deploy-tradein.yml его не дёргали. Для правки, чья главная логика
живёт в конфиге прокси, это единственный настоящий гейт — и он был асинхронным: регресс
жил до суток и находил его либо ночной прогон, либо владелец.

Что сделано

Job perimeter-smoke в обоих пайплайнах. Конфиг прокси (deploy.yml) и фронт МЕРЫ
(deploy-tradein.yml) едут раздельно — сломать периметр может каждый.

Три решения, которые стоит назвать:

  • Отдельный job, а не шаг внутри deploy. «Выкатили» и «периметр цел» — разные
    вердикты; красный смоук не должен читаться как неудавшийся деплой.
  • if: needs.deploy.result == 'success'. Поверх пропущенной или упавшей выкатки
    проверять нечего, а красный смоук увёл бы разбор не туда.
  • Ожидание готовности по двум признакам (лэндинг 200 и API 401) до 150 с.
    up -d --force-recreate отдаёт управление раньше, чем бэкенд отвечает; без ожидания
    смоук ловил бы гонку, а не регресс. Одного признака мало — Caddy отвечает раньше апстрима.
    По таймауту шаг не падает, а печатает warning и пускает смоук: иначе «не успел
    подняться» и «периметр сломан» слились бы в один красный шаг без диагноза.

Дублирование 20 строк в двух файлах — осознанное: workflow_call под act_runner не
гарантирован, а зависимость, которая может молча не сработать, здесь хуже повтора.

Смежные пункты задачи

Скрипт не линтовался ничем. shellcheck в репозитории нет, поэтому в ci.yml добавлен
гейт bash -n на все shell-скрипты — сейчас их 14, все валидны. Гейт падает, если не
нашёл ни одного файла
: пустая маска дала бы зелёный шаг, который ничего не проверяет
(#2871 ровно про это). Граница названа в комментарии: bash -n ловит синтаксис, а не смысл.

Правка смоука проверяется сразу — в perimeter-smoke.yml добавлен push-триггер на сам
скрипт и на workflow.

Про внешний геокодер — опасение проверено и оказалось у́же, чем звучит. В задаче
предполагалось, что падение/квота DaData дадут красный «регресс периметра». По коду
services/geocoder.py это цепочка «кадастровый тир → DaData → Nominatim → []», и каждый
внешний тир обёрнут в except Exception: отказ, квота и 5xx дают пустой список и HTTP
200
, проверка остаётся зелёной. Покраснеть она может только если провайдер виснет
дольше 15 с (--max-time у curl) — то есть на зависании, а не на отказе.

Ожидание не ослаблял: 200 здесь проверяет открытость пути анониму, ради которой проверка
и написана. Вывод записан в самом скрипте, чтобы следующий читатель не разбирал это заново.

Проверка

Прогнал смоук против прода перед правкой — 27 из 27 зелёные:

PASS: meraocenka.ru root / oferta / refund / privacy / estimate — 200
PASS: длинные адреса — 301 на короткие (включая голый /trade-in/mera-public)
PASS: /v2, /trade-in/v2, /trade-in/api/*, /_next/image — 404
PASS: public suggest + coverage — 200 анонимно, v1 на публичном домене — 404
PASS: /api/v1/me, /history, /admin/* — 401 · gendsgn.ru/api/v1/admin/* — 401
PASS: merahome.ru, meraotsenka.ru — 301 на канонический
PASS: платёжный периметр — 404/401 (канарейка до PR-D3/D4)
ALL CHECKS PASSED

То есть в пайплайн въезжает работающий гейт, а не заведомо красный.

  • yaml.safe_load всех четырёх файлов — валидны, состав job'ов проверен разбором
  • bash -n по 14 скриптам локально — чисто
  • цикл ожидания прогнан отдельно против прода — сходится с первой попытки

Closes #2917

## Что было `scripts/smoke-mera-perimeter.sh` — единственная проверка, которая видит публичный периметр целиком: короткие адреса, 301 с длинных, публичный API, закрытость B2B-путей на публичном домене. Запускался он только по `workflow_dispatch` и ночному cron'у `17 6 * * *`. Ни `deploy.yml`, ни `deploy-tradein.yml` его не дёргали. Для правки, чья главная логика живёт в конфиге прокси, это **единственный настоящий гейт — и он был асинхронным**: регресс жил до суток и находил его либо ночной прогон, либо владелец. ## Что сделано **Job `perimeter-smoke` в обоих пайплайнах.** Конфиг прокси (`deploy.yml`) и фронт МЕРЫ (`deploy-tradein.yml`) едут раздельно — сломать периметр может каждый. Три решения, которые стоит назвать: - **Отдельный job, а не шаг внутри `deploy`.** «Выкатили» и «периметр цел» — разные вердикты; красный смоук не должен читаться как неудавшийся деплой. - **`if: needs.deploy.result == 'success'`.** Поверх пропущенной или упавшей выкатки проверять нечего, а красный смоук увёл бы разбор не туда. - **Ожидание готовности по двум признакам** (лэндинг 200 **и** API 401) до 150 с. `up -d --force-recreate` отдаёт управление раньше, чем бэкенд отвечает; без ожидания смоук ловил бы гонку, а не регресс. Одного признака мало — Caddy отвечает раньше апстрима. По таймауту шаг **не падает**, а печатает warning и пускает смоук: иначе «не успел подняться» и «периметр сломан» слились бы в один красный шаг без диагноза. Дублирование 20 строк в двух файлах — осознанное: `workflow_call` под `act_runner` не гарантирован, а зависимость, которая может молча не сработать, здесь хуже повтора. ## Смежные пункты задачи **Скрипт не линтовался ничем.** `shellcheck` в репозитории нет, поэтому в `ci.yml` добавлен гейт `bash -n` на все shell-скрипты — сейчас их 14, все валидны. Гейт **падает, если не нашёл ни одного файла**: пустая маска дала бы зелёный шаг, который ничего не проверяет (#2871 ровно про это). Граница названа в комментарии: `bash -n` ловит синтаксис, а не смысл. **Правка смоука проверяется сразу** — в `perimeter-smoke.yml` добавлен push-триггер на сам скрипт и на workflow. **Про внешний геокодер — опасение проверено и оказалось у́же, чем звучит.** В задаче предполагалось, что падение/квота DaData дадут красный «регресс периметра». По коду `services/geocoder.py` это цепочка «кадастровый тир → DaData → Nominatim → `[]`», и каждый внешний тир обёрнут в `except Exception`: отказ, квота и 5xx дают пустой список и **HTTP 200**, проверка остаётся зелёной. Покраснеть она может только если провайдер **виснет** дольше 15 с (`--max-time` у curl) — то есть на зависании, а не на отказе. Ожидание не ослаблял: `200` здесь проверяет открытость пути анониму, ради которой проверка и написана. Вывод записан в самом скрипте, чтобы следующий читатель не разбирал это заново. ## Проверка Прогнал смоук против прода перед правкой — **27 из 27 зелёные**: ``` PASS: meraocenka.ru root / oferta / refund / privacy / estimate — 200 PASS: длинные адреса — 301 на короткие (включая голый /trade-in/mera-public) PASS: /v2, /trade-in/v2, /trade-in/api/*, /_next/image — 404 PASS: public suggest + coverage — 200 анонимно, v1 на публичном домене — 404 PASS: /api/v1/me, /history, /admin/* — 401 · gendsgn.ru/api/v1/admin/* — 401 PASS: merahome.ru, meraotsenka.ru — 301 на канонический PASS: платёжный периметр — 404/401 (канарейка до PR-D3/D4) ALL CHECKS PASSED ``` То есть в пайплайн въезжает **работающий** гейт, а не заведомо красный. - [x] `yaml.safe_load` всех четырёх файлов — валидны, состав job'ов проверен разбором - [x] `bash -n` по 14 скриптам локально — чисто - [x] цикл ожидания прогнан отдельно против прода — сходится с первой попытки Closes #2917
bot-backend added 1 commit 2026-08-19 07:56:42 +00:00
ci: смоук периметра МЕРЫ запускается сразу после деплоя
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
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) Successful in 1m14s
CI / openapi-codegen-check (pull_request) Successful in 2m8s
CI / backend-tests (pull_request) Successful in 16m22s
db03e93781
scripts/smoke-mera-perimeter.sh — единственная проверка, которая видит
публичный периметр целиком (короткие адреса, 301 с длинных, публичный API,
закрытость B2B-путей на публичном домене). Запускался он только ночным
cron'ом 06:17 UTC, поэтому регресс жил до суток, и находил его либо тот же
cron, либо владелец — ровно тот сценарий, против которого проверки и писались.

Добавлен job `perimeter-smoke` в ОБА пайплайна: конфиг прокси (deploy.yml) и
фронт МЕРЫ (deploy-tradein.yml) едут раздельно, сломать периметр может каждый.
Отдельный job, а не шаг внутри deploy: «выкатили» и «периметр цел» — два
разных вердикта, красный смоук не должен читаться как неудавшийся деплой.
Идёт только при deploy.result == 'success' — поверх несостоявшейся выкатки
проверять нечего.

Перед смоуком — ожидание готовности по ДВУМ признакам (лэндинг 200 и API 401):
`up -d --force-recreate` отдаёт управление раньше, чем бэкенд начинает
отвечать, и без ожидания смоук ловил бы гонку, а не регресс. По истечении
150 с ожидание не падает, а печатает warning и пускает смоук — иначе
«не успел подняться» и «периметр сломан» слились бы в один красный шаг.

Дублирование 20 строк в двух пайплайнах осознанное: `workflow_call` под
act_runner не гарантирован, а зависимость, которая может молча не сработать,
здесь хуже повтора.

Заодно:
- ci.yml: гейт `bash -n` на все shell-скрипты (14 файлов) — shellcheck'а в
  репозитории нет, а опечатка в смоуке обнаружилась бы следующим утром и
  выглядела бы как регресс периметра. Гейт падает, если не нашёл ни одного
  файла: пустая маска дала бы зелёный шаг, который ничего не проверяет.
- perimeter-smoke.yml: push-триггер на сам скрипт — правка проверяется сразу.

Проверено: смоук против прода сейчас зелёный целиком, 27 из 27 проверок,
то есть в пайплайн въезжает работающий гейт, а не заведомо красный.

Опасение из задачи про внешний геокодер проверено по коду и оказалось у́же:
`geocoder.suggest` — цепочка «кадастр → DaData → Nominatim → []», каждый
внешний тир под `except Exception`, отказ и квота дают 200 с пустым списком.
Покраснеть проверка может только на зависании дольше 15 с. Записал это в
самом скрипте, ожидание не ослаблял.

Closes #2917
bot-backend merged commit e86f0782da into main 2026-08-19 08:13:50 +00:00
bot-backend deleted branch ci/2917-perimeter-smoke-after-deploy 2026-08-19 08:13:50 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#2922
No description provided.