From 49a3962e6bbb23306e3d2beb33cf0eee99c75a6c Mon Sep 17 00:00:00 2001 From: bot-backend Date: Fri, 7 Aug 2026 03:34:57 +0500 Subject: [PATCH] =?UTF-8?q?fix(devops):=20=D0=B4=D0=B0=D1=82=D1=8C=20trade?= =?UTF-8?q?-in=20=D1=81=D0=B2=D1=8F=D0=B7=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=D1=81=20redis,=20=D0=BF=D0=BE=D1=82=D0=BE=D0=BC=20=D1=83=D0=B6?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=82=D1=8C=20REDIS=5FURL=20(?= =?UTF-8?q?#2709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема была не в незаданной переменной, а в отсутствующей связности: gendesign-redis-1 жил только в gendesign_default, tradein-backend — в gendesign_shared + tradein-net. Общей сети нет → redis не резолвился ни под каким именем. Вводим redis в gendesign_shared под алиасом gendesign-redis (тот же приём, что уже применён к postgres) и только после этого задаём REDIS_URL на db1 (db0 занят celery-брокером gendesign, db2 — glitchtip). Порядок «сначала сеть, потом переменная» соблюдён буквально: связность проверена на проде throwaway-контейнером ДО того, как переменная где-либо появилась (из tradein-backend: PING 19 мс, SET 0.35 мс, GET 0.31 мс, db1). Цена ошибки измерена тем же клиентом, что в app/services/cache.py: localhost-отказ 16.6 мс (как было), NXDOMAIN 123.5 мс, а имя, которое резолвится и не отвечает — 2003.7 мс. Последнее и есть та молчаливая яма, про которую предупреждает issue: ×2 (GET+SET) на каждый запрос, без ошибки наверх, потому что get/set глотают исключение. Свой redis в стеке trade-in НЕ добавлен осознанно: deploy-tradein.yml поднимает стек как `up -d --no-deps $SERVICES` с ЗАХАРДКОЖЕННЫМ списком (browser backend frontend tgbot [scraper]). Новый сервис туда не попадает и `--no-deps` его не подтянет — контейнер никогда бы не стартовал, а REDIS_URL указывал бы в пустоту. Правка списка = правка deploy-tradein.yml, который сейчас заморожен (#2680). Ожидаемый выигрыш по скорости — НУЛЕВОЙ, и это измерено, а не оценено: POST /api/v1/search за 16.2 суток логов Caddy получил 0 запросов, и во фронтенде нет ни одного вызова этого роута. Реальная ценность правки — снять заряженную ловушку и дать #2665 (потолок темпа логинов) хранилище с ПРОВЕРЕННОЙ доступностью, чего issue прямо и требует. Refs #2709, #2674, #2665 --- docker-compose.prod.yml | 34 +++++++++++++++++++++++++++++ tradein-mvp/docker-compose.prod.yml | 15 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 38733e49..9e04bd6b 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -111,6 +111,40 @@ services: interval: 10s timeout: 3s retries: 5 + # #2709: redis вводится в gendesign_shared, чтобы tradein-backend вообще МОГ + # его достать. До этого redis жил только в gendesign_default, а tradein — в + # gendesign_shared + tradein-net: общей сети НЕТ, поэтому REDIS_URL там не + # резолвился НИ ПОД КАКИМ именем. Это была не «забытая переменная», а + # отсутствующая связность (см. #2709). + # + # Почему общий инстанс, а не свой redis в стеке trade-in: deploy-tradein.yml + # поднимает стек как `up -d --no-deps $SERVICES`, где SERVICES — + # ЗАХАРДКОЖЕННЫЙ список (browser backend frontend tgbot [scraper]). Новый + # сервис в tradein-compose в этот список не попадает и `--no-deps` его не + # подтянет → контейнер просто никогда бы не стартовал, а REDIS_URL указывал + # бы в пустоту. Правка того списка = правка deploy-tradein.yml, который + # сейчас заморожен (#2680 ждёт человека). Общий инстанс обходит это целиком. + # + # aliases: тот же приём, что уже применён к postgres выше — стабильное имя + # gendesign-redis вместо compose-зависимого gendesign-redis-1. + # ⚠️ `default` ОБЯЗАН быть перечислен явно: как только у сервиса появляется + # блок networks:, неявная привязка к default пропадает, и backend/worker/ + # beat/glitchtip потеряли бы брокер (та же грабля описана у postgres). + # + # Разделение ключей — по НОМЕРУ БД, инстанс общий: + # db0 — gendesign (celery-брокер + кэши бэкенда), 2166 ключей + # db1 — trade-in (SearchCache) ← вводится здесь + # db2 — glitchtip (см. REDIS_URL ниже) + # Ceiling: maxmemory=0 / noeviction на инстансе НЕ трогаем — allkeys-lru на + # брокере celery вытеснял бы поставленные в очередь таски. Значит tradein + # обязан ставить TTL на каждый ключ (он ставит: SET ... ex=ttl). Если + # tradein когда-нибудь начнёт писать без TTL, упрётся весь инстанс, включая + # celery. Тогда — отдельный инстанс, а не смена политики вытеснения. + networks: + default: {} + shared: + aliases: + - gendesign-redis # OSRM routing engine (#39 — site-finder /analyze road/walking distances to POI # вместо straight-line ST_Distance). INFRA-only здесь: интеграция в /analyze — diff --git a/tradein-mvp/docker-compose.prod.yml b/tradein-mvp/docker-compose.prod.yml index b7e602a8..c68d74c2 100644 --- a/tradein-mvp/docker-compose.prod.yml +++ b/tradein-mvp/docker-compose.prod.yml @@ -206,6 +206,21 @@ services: # Значение ДОЛЖНО совпадать с TRADEIN_INTERNAL_AUTH_SECRET в .env главного # (Caddy) стека. Читается также из backend/.env.runtime (env_file выше). TRADEIN_INTERNAL_AUTH_SECRET: "${TRADEIN_INTERNAL_AUTH_SECRET:-}" + # #2709. Дефолт в коде — redis://localhost:6379/0, и внутри контейнера это + # мгновенный ConnectionRefused (замер: 16.6 мс) → кэш не работал ни дня. + # ⚠️ ПОРЯДОК КРИТИЧЕН, и цена ошибки измерена тем же клиентом, что в + # app/services/cache.py (socket_timeout=2.0, socket_connect_timeout=2.0): + # localhost, отказ соединения 16.6 мс ← как было + # имя не резолвится (NXDOMAIN) 123.5 мс + # имя резолвится, но не отвечает 2003.7 мс ← вот эта яма + # get/set глотают исключение в logger.warning и возвращают промах, поэтому + # яма МОЛЧАЛИВАЯ: 2 с на GET + 2 с на SET на каждый запрос, без единой + # ошибки наверх. Отсюда правило: сначала связность, потом переменная. + # Здесь она задаётся только потому, что связность уже проверена на проде + # ДО этой строки (throwaway-redis на gendesign_shared, из tradein-backend: + # PING 19 мс, SET 0.35 мс, GET 0.31 мс) — см. описание PR. + # db1 — не 0 и не 2: 0 занят celery-брокером gendesign, 2 — glitchtip'ом. + REDIS_URL: "redis://gendesign-redis:6379/1" depends_on: browser: condition: service_started -- 2.45.3