From d177b916e34657ba890b326090498a2383bfd082 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sat, 5 Sep 2026 22:48:54 +0500 Subject: [PATCH 1/2] =?UTF-8?q?fix(caddy):=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D0=B0=20=C2=AB=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=8F=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=C2=BB=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20?= =?UTF-8?q?=D0=B3=D0=BE=D0=BB=D0=BE=D0=B3=D0=BE=20502=20=D0=B2=20=D0=BE?= =?UTF-8?q?=D0=BA=D0=BD=D0=B5=20=D0=B4=D0=B5=D0=BF=D0=BB=D0=BE=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Каждый мерж в 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 --- caddy/deploy-window.caddy.snippet | 54 +++++++++++++++++++++++++++++++ caddy/sites/apps.caddy | 39 ++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 caddy/deploy-window.caddy.snippet diff --git a/caddy/deploy-window.caddy.snippet b/caddy/deploy-window.caddy.snippet new file mode 100644 index 00000000..971464de --- /dev/null +++ b/caddy/deploy-window.caddy.snippet @@ -0,0 +1,54 @@ +# ═══════════════════════════════════════════════════════════════════════════ +# caddy/deploy-window.caddy.snippet — ответ на окно деплоя (#3274) +# +# Импортируется ВНУТРЬ `handle_errors 502 503 504 { ... }` (см. apps.caddy): +# сам по себе снипет ничего не перехватывает, он только решает, ЧТО отдать, +# когда апстрим не отвечает. +# +# ЧТО ЭТО ЛЕЧИТ, А ЧТО НЕТ. Каждый деплой tradein-frontend/tradein-backend +# оставляет окно 30–90 с, в котором контейнера просто нет: 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=` вместо блока `