gendesign/caddy/deploy-window.caddy.snippet
bot-backend d177b916e3
Some checks failed
CI Trade-In / changes (pull_request) Successful in 11s
CI / changes (pull_request) Failing after 12s
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 / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
fix(caddy): страница «сервис обновляется» вместо голого 502 в окне деплоя
Каждый мерж в tradein оставляет 30-90 с, в которые контейнера нет и Caddy
набирает несуществующий апстрим: 15 x 502 на meraocenka.ru и 23 на gendsgn.ru
за 4 суток, все на окнах деплоя (duration < 2 мс = мгновенный отказ
соединения, а не перегрузка).

handle_errors 502/503/504 подменяет это на 503 + Retry-After: 30 и читаемое
тело. 502 читается как постоянная поломка — поисковик выкидывает страницу из
индекса, клиенты не ретраят; 503 + Retry-After означает ровно то, что
происходит. Для /trade-in/api/* тело JSON, а не HTML: эти ручки вызывают из JS
и внешних клиентов, HTML у них превращается в ошибку разбора.

На gendsgn.ru перехват гейтится по пути /trade-in* — Site Finder («Птица»)
деплоится отдельным пайплайном и в задачу не входит; вне матчера ошибка
остаётся необработанной и поведение прежнее.

Окно простоя это НЕ убирает — zero-downtime деплой (п.1 issue) требует
решения владельца. Меняется только то, что видно внутри окна.

Refs #3274
2026-09-05 22:48:54 +05:00

54 lines
4.3 KiB
Text
Raw Permalink 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.

# ═══════════════════════════════════════════════════════════════════════════
# caddy/deploy-window.caddy.snippet — ответ на окно деплоя (#3274)
#
# Импортируется ВНУТРЬ `handle_errors 502 503 504 { ... }` (см. apps.caddy):
# сам по себе снипет ничего не перехватывает, он только решает, ЧТО отдать,
# когда апстрим не отвечает.
#
# ЧТО ЭТО ЛЕЧИТ, А ЧТО НЕТ. Каждый деплой tradein-frontend/tradein-backend
# оставляет окно 3090 с, в котором контейнера просто нет: Caddy набирает
# новый апстрим сразу, тот ещё не слушает (замер по access-логам, #3274 —
# все 502 кластеризуются на окнах мержа, duration < 2 мс = мгновенный отказ
# соединения). Снипет НЕ УБИРАЕТ окно — он меняет то, что видит человек и
# клиент внутри окна. Настоящее лечение (готовность нового контейнера до
# переключения) — п.1 issue, решение владельца, здесь его нет.
#
# ПОЧЕМУ 503, А НЕ 502. 502 значит «апстрим ответил мусором» — постоянная
# поломка; поисковик по нему выкидывает страницу из индекса, клиентские
# библиотеки не ретраят. 503 + `Retry-After: 30` — стандартный код «временно
# недоступен, приходи через 30 секунд»: Googlebot держит страницу в индексе,
# HTTP-клиенты понимают, что повтор осмыслен.
#
# ПОЧЕМУ ДВА ТЕЛА. `/trade-in/api/*` вызывают из JS и внешних клиентов — они
# парсят JSON, и HTML-страница у них превращается в ошибку разбора вместо
# читаемого статуса. Всё остальное открывает человек браузером.
#
# ВНЕШНИХ РЕСУРСОВ В СТРАНИЦЕ НЕТ ВООБЩЕ — ни шрифта, ни CSS-файла, ни
# картинки. В окне деплоя они пришли бы с того же мёртвого апстрима, и
# страница-заглушка отрисовалась бы голым текстом. Отсюда же инлайновые
# `style=` вместо блока `<style>`: фигурные скобки в теле `respond` Caddy
# пытается разобрать как плейсхолдеры.
# ═══════════════════════════════════════════════════════════════════════════
@deployWindowApi path /trade-in/api/*
handle @deployWindowApi {
header Content-Type "application/json; charset=utf-8"
header Retry-After "30"
respond `{"detail":"Сервис обновляется, повторите запрос через минуту","error":"service_unavailable","retry_after":30}` 503
}
handle {
header Content-Type "text/html; charset=utf-8"
header Retry-After "30"
respond `<!doctype html>
<html lang="ru">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Сервис обновляется</title>
<body style="margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;background:#fff;color:#111">
<main style="max-width:30rem;padding:2rem;text-align:center">
<h1 style="font-size:1.25rem;font-weight:600;margin:0 0 .75rem">Сервис обновляется</h1>
<p style="margin:0;line-height:1.6;color:#444">Это занимает около минуты. Обновите страницу чуть позже — введённые данные не потеряются.</p>
</main>
` 503
}