fix(deploy): правки ревью гейта ПТИЦЫ — таймаут сессии, crash-loop, множественный id (#3324)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 2m4s
CI / backend-tests (pull_request) Successful in 17m35s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 2m4s
CI / backend-tests (pull_request) Successful in 17m35s
command_timeout: 30m — дефолт appleboy/ssh-action 10m короче worst-case гейта (~17 мин), сессию убило бы посреди диагноза и авария читалась бы обрывом связи. Деградация «нет health-конфига» требовала лишь running дважды: crash-loop с временем жизни больше паузы проходил как стабильный (обе проверки видят running, просто это разные жизни контейнера). Теперь сверяется RestartCount до/после окна 15 с; окно учитывается в счётчике ожидания, иначе таймаут 240 с растянулся бы на ~24 мин и упёрся в command_timeout. cid(): `ps -aq` возвращает несколько id при залежавшемся exited-контейнере → docker inspect падает → пустой статус → ложный красный. tail -n1. worker healthcheck: убран `2>&1` (глушил причину, которую деплой печатает из .State.Health.Log), retries 3→5 — при interval 60s тройка промахов = 3 минуты, столько длится обычный флап Redis, а из unhealthy контейнер сам не выходит.
This commit is contained in:
parent
13c4420d1f
commit
1b1977efa3
2 changed files with 34 additions and 8 deletions
|
|
@ -596,6 +596,11 @@ jobs:
|
||||||
# #3029: подлинность хоста. Секрет НЕ задан → пустая строка → easyssh-proxy
|
# #3029: подлинность хоста. Секрет НЕ задан → пустая строка → easyssh-proxy
|
||||||
# оставляет ssh.InsecureIgnoreHostKey(), то есть сегодняшнее поведение.
|
# оставляет ssh.InsecureIgnoreHostKey(), то есть сегодняшнее поведение.
|
||||||
fingerprint: ${{ secrets.DEPLOY_SSH_FINGERPRINT }}
|
fingerprint: ${{ secrets.DEPLOY_SSH_FINGERPRINT }}
|
||||||
|
# #3324: дефолт appleboy/ssh-action — command_timeout 10m, а worst-case
|
||||||
|
# гейта в конце скрипта ~17 мин (4 сервиса × 240s ожидания healthy +
|
||||||
|
# фронт + diagnose). Сессию убило бы посреди печати диагноза, и авария
|
||||||
|
# выглядела бы обрывом связи, а не мёртвым контейнером.
|
||||||
|
command_timeout: 30m
|
||||||
envs: IMAGE_TAG,SENTRY_RELEASE_VAL,GHCR_PAT,GLITCHTIP_BACKEND_DSN,OBJECTIVE_API_KEY,OPENAI_API_KEY,LLM_ENABLED,OWN_DEVELOPER_IDS,WORKER_RECREATE_GUARD,WORKER_GUARD_MAX_SKIP_H
|
envs: IMAGE_TAG,SENTRY_RELEASE_VAL,GHCR_PAT,GLITCHTIP_BACKEND_DSN,OBJECTIVE_API_KEY,OPENAI_API_KEY,LLM_ENABLED,OWN_DEVELOPER_IDS,WORKER_RECREATE_GUARD,WORKER_GUARD_MAX_SKIP_H
|
||||||
script: |
|
script: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
@ -1052,7 +1057,11 @@ jobs:
|
||||||
# ломая порядок «миграции до подъёма кода». Читаем состояние явно.
|
# ломая порядок «миграции до подъёма кода». Читаем состояние явно.
|
||||||
# Все проверки выполняются ДО выхода (не падаем на первой) — один
|
# Все проверки выполняются ДО выхода (не падаем на первой) — один
|
||||||
# прогон обязан показать ВСЕ поломанные сервисы, а не первый по списку.
|
# прогон обязан показать ВСЕ поломанные сервисы, а не первый по списку.
|
||||||
cid() { docker compose -p gendesign -f docker-compose.prod.yml ps -aq "$1" 2>/dev/null || true; }
|
# tail -n1: у сервиса может остаться залежавшийся exited-контейнер, и
|
||||||
|
# тогда `ps -aq` вернёт НЕСКОЛЬКО id через \n — `docker inspect` с таким
|
||||||
|
# аргументом падает, статус приходит пустым и гейт краснеет на ровном
|
||||||
|
# месте. Последний id — самый свежий контейнер сервиса.
|
||||||
|
cid() { docker compose -p gendesign -f docker-compose.prod.yml ps -aq "$1" 2>/dev/null | tail -n1 || true; }
|
||||||
|
|
||||||
diagnose() { # $1 сервис, $2 id контейнера (может быть пустым)
|
diagnose() { # $1 сервис, $2 id контейнера (может быть пустым)
|
||||||
local svc="$1" c="$2"
|
local svc="$1" c="$2"
|
||||||
|
|
@ -1070,7 +1079,7 @@ jobs:
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_healthy() { # $1 сервис, $2 таймаут, с
|
wait_healthy() { # $1 сервис, $2 таймаут, с
|
||||||
local svc="$1" deadline="$2" c="" status="" alive="" waited=0
|
local svc="$1" deadline="$2" c="" status="" alive="" r0="" r1="" waited=0
|
||||||
while [ "$waited" -lt "$deadline" ]; do
|
while [ "$waited" -lt "$deadline" ]; do
|
||||||
c="$(cid "$svc")"
|
c="$(cid "$svc")"
|
||||||
if [ -n "$c" ]; then
|
if [ -n "$c" ]; then
|
||||||
|
|
@ -1086,12 +1095,24 @@ jobs:
|
||||||
# worker, пропущенный guard'ом #3029). Валить деплой за это
|
# worker, пропущенный guard'ом #3029). Валить деплой за это
|
||||||
# нельзя, но и молчать нельзя: падаем на «стабильный running»
|
# нельзя, но и молчать нельзя: падаем на «стабильный running»
|
||||||
# (двойное чтение, как tgbot/scraper в deploy-tradein.yml).
|
# (двойное чтение, как tgbot/scraper в deploy-tradein.yml).
|
||||||
sleep 3
|
# Одного `running` дважды НЕДОСТАТОЧНО: crash-loop с временем
|
||||||
|
# жизни больше паузы читается как «стабилен» — контейнер оба
|
||||||
|
# раза running, просто это разные его жизни. Поэтому вместе со
|
||||||
|
# статусом сверяем RestartCount: изменился за окно = именно
|
||||||
|
# тот дефект, ради которого этот гейт и писался.
|
||||||
|
r0="$(docker inspect -f '{{.RestartCount}}' "$c" 2>/dev/null || echo '')"
|
||||||
|
sleep 15
|
||||||
alive="$(docker inspect -f '{{.State.Status}}' "$c" 2>/dev/null || echo unknown)"
|
alive="$(docker inspect -f '{{.State.Status}}' "$c" 2>/dev/null || echo unknown)"
|
||||||
if [ "$alive" = "running" ]; then
|
r1="$(docker inspect -f '{{.RestartCount}}' "$c" 2>/dev/null || echo '')"
|
||||||
echo "→ $svc: healthcheck не сконфигурирован (контейнер не пересоздавался), running стабилен"
|
if [ "$alive" = "running" ] && [ -n "$r0" ] && [ "$r0" = "$r1" ]; then
|
||||||
|
echo "→ $svc: healthcheck не сконфигурирован (контейнер не пересоздавался), running стабилен (RestartCount=$r0 не изменился за 15s)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
# waited растёт на длину ЭТОЙ паузы тоже — иначе таймаут
|
||||||
|
# 240s превратился бы в ~24 минуты реального ожидания и упёрся
|
||||||
|
# бы в command_timeout SSH-сессии.
|
||||||
|
waited=$((waited + 15))
|
||||||
|
echo " $svc: running нестабилен — status='$alive', RestartCount ${r0:-<нет>}→${r1:-<нет>} (контейнер перезапускался внутри окна наблюдения); продолжаю ждать"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -325,12 +325,17 @@ services:
|
||||||
# Интервал 60s (не 30s как у backend): каждая проба — отдельный запуск
|
# Интервал 60s (не 30s как у backend): каждая проба — отдельный запуск
|
||||||
# celery-CLI с импортом приложения, дешёвым его не назовёшь.
|
# celery-CLI с импортом приложения, дешёвым его не назовёшь.
|
||||||
# start_period 90s: холодный старт worker'а с Chromium-образа заметно
|
# start_period 90s: холодный старт worker'а с Chromium-образа заметно
|
||||||
# медленнее backend'а. 3 промаха подряд (~3 мин) → unhealthy.
|
# медленнее backend'а.
|
||||||
|
# stderr НЕ глушим: docker хранит вывод пробы в .State.Health.Log, и деплой
|
||||||
|
# печатает его в диагнозе — с `2>&1` там была бы пустота вместо причины.
|
||||||
|
# retries 5 (не 3): при interval 60s тройка промахов = 3 минуты, столько
|
||||||
|
# длится обычный флап Redis, а из unhealthy контейнер сам не выходит по
|
||||||
|
# restart-политике — следующий деплой краснел бы за исправный воркер.
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "celery -A app.workers.celery_app inspect ping -d celery@$$(hostname) -t 10 >/dev/null 2>&1"]
|
test: ["CMD-SHELL", "celery -A app.workers.celery_app inspect ping -d celery@$$(hostname) -t 10 >/dev/null"]
|
||||||
interval: 60s
|
interval: 60s
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
retries: 3
|
retries: 5
|
||||||
start_period: 90s
|
start_period: 90s
|
||||||
# #976 cross-DB ETL tradein→gendesign: worker запускает etl_newbuilding_crossload task,
|
# #976 cross-DB ETL tradein→gendesign: worker запускает etl_newbuilding_crossload task,
|
||||||
# которому нужен прямой TCP-доступ к tradein-postgres через gendesign_shared.
|
# которому нужен прямой TCP-доступ к tradein-postgres через gendesign_shared.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue