Переезд: на Poincare не задан TRADEIN_DATABASE_URL — newbuilding-crossload молча грузит 0 лотов вместо ~11 000/сут #3094

Closed
opened 2026-08-26 05:35:26 +00:00 by lekss361 · 1 comment
Owner

Что сломано

Первый же прогон newbuilding-crossload на Poincare (run_id=84, 2026-08-25 21:30 UTC) отработал за 12 мс и загрузил 0 лотов. Предыдущие прогоны на Beget давали стабильно ~11 000:

run_id когда rows_lots error
84 08-25 21:30 (Poincare) 0 TRADEIN_DATABASE_URL not set
82 08-24 21:30 (Beget) 11 212
08-23 21:30 11 174
08-22 21:30 11 076

Причина

Переменная TRADEIN_DATABASE_URL не доехала в backend/.env на Poincare. Проверено по контейнерам — ключей TRADEIN_* ноль в gendesign-worker-1, gendesign-beat-1, gendesign-backend-1 (сверка по именам ключей docker inspect, значения не читались).

Сеть при этом в порядке — установки одной переменной достаточно: gendesign_shared существует, в ней одновременно и gendesign-worker-1, и tradein-postgres, так что TCP-путь для cross-DB ETL есть.

Почему это не заметили

backend/app/workers/tasks/etl_newbuilding_crossload.py:87:

if result.get("disabled"):
    _finish_run(db, run_id, status="done", error="TRADEIN_DATABASE_URL not set")

Несработавшая предпосылка записывается статусом done. Потерянный конфиг неотличим от осознанно выключенной фичи, поэтому ни мониторинг, ни GlitchTip ничего не увидели — ровно та же ловушка, из-за которой в тестах завели skip_allowlist.txt: пропуск без записи неотличим от пройденной проверки.

Радиус ограничен: паттерн «молча выключиться без переменной» в backend/app/ встречается только здесь (плюс LLM-клиент со своей fallback-семантикой).

Что нужно

  1. Владельцу (значение — секрет, ботом не трогается): добавить TRADEIN_DATABASE_URL в backend/.env на Poincare (DSN на локальный tradein-postgres в сети gendesign_shared), затем docker compose up -d worker beat. Проверка — ближайший прогон в 21:30 UTC должен дать rows_lots порядка 11 000.
  2. Кодом (отдельный PR): отличать «выключено осознанно» от «конфиг потерян». Вариант с наименьшим радиусом — отдельный статус для несработавшей предпосылки, чтобы прогон с нулём был видим сверху. Выбор семантики статуса — за владельцем, поэтому PR не открываю до решения.

Как нашлось

Побочно при сверке старого кластера на Beget с живым на Poincare перед удалением устаревших копий БД: у Poincare нашёлся прогон, которого нет на Beget, и он оказался пустым.

## Что сломано Первый же прогон `newbuilding-crossload` на Poincare (`run_id=84`, 2026-08-25 21:30 UTC) отработал за **12 мс** и загрузил **0 лотов**. Предыдущие прогоны на Beget давали стабильно ~11 000: | run_id | когда | rows_lots | error | |---|---|---|---| | 84 | 08-25 21:30 (Poincare) | **0** | `TRADEIN_DATABASE_URL not set` | | 82 | 08-24 21:30 (Beget) | 11 212 | — | | — | 08-23 21:30 | 11 174 | — | | — | 08-22 21:30 | 11 076 | — | ## Причина Переменная `TRADEIN_DATABASE_URL` не доехала в `backend/.env` на Poincare. Проверено по контейнерам — ключей `TRADEIN_*` **ноль** в `gendesign-worker-1`, `gendesign-beat-1`, `gendesign-backend-1` (сверка по именам ключей `docker inspect`, значения не читались). Сеть при этом в порядке — установки одной переменной достаточно: `gendesign_shared` существует, в ней одновременно и `gendesign-worker-1`, и `tradein-postgres`, так что TCP-путь для cross-DB ETL есть. ## Почему это не заметили `backend/app/workers/tasks/etl_newbuilding_crossload.py:87`: ```python if result.get("disabled"): _finish_run(db, run_id, status="done", error="TRADEIN_DATABASE_URL not set") ``` Несработавшая предпосылка записывается статусом **`done`**. Потерянный конфиг неотличим от осознанно выключенной фичи, поэтому ни мониторинг, ни GlitchTip ничего не увидели — ровно та же ловушка, из-за которой в тестах завели `skip_allowlist.txt`: пропуск без записи неотличим от пройденной проверки. Радиус ограничен: паттерн «молча выключиться без переменной» в `backend/app/` встречается **только** здесь (плюс LLM-клиент со своей fallback-семантикой). ## Что нужно 1. **Владельцу (значение — секрет, ботом не трогается):** добавить `TRADEIN_DATABASE_URL` в `backend/.env` на Poincare (DSN на локальный `tradein-postgres` в сети `gendesign_shared`), затем `docker compose up -d worker beat`. Проверка — ближайший прогон в 21:30 UTC должен дать `rows_lots` порядка 11 000. 2. **Кодом (отдельный PR):** отличать «выключено осознанно» от «конфиг потерян». Вариант с наименьшим радиусом — отдельный статус для несработавшей предпосылки, чтобы прогон с нулём был видим сверху. Выбор семантики статуса — за владельцем, поэтому PR не открываю до решения. ## Как нашлось Побочно при сверке старого кластера на Beget с живым на Poincare перед удалением устаревших копий БД: у Poincare нашёлся прогон, которого нет на Beget, и он оказался пустым.
Author
Owner

Закрыто — переменная долита, коннект проверен живым запросом.

Причина была не в секретах CI, а в runtime-файле окружения на хосте: копия на Poincare оказалась беднее оригинала (18 переменных против 31). Долито 8 ключей хост-к-хосту, значения в логи и переписку не попадали — только имена и счётчики. Права сохранены через chown/chmod --reference: 600 gendesign:gendesign.

Проверка изнутри gendesign-backend-1 (26.08, 06:2x UTC):

переменная задана: True | длина: 108
хост назначения: tradein-postgres
КОННЕКТ OK, listings: 109543

Сверка окружения с эталоном: Beget 31 переменная, Poincare 31, расхождений нет. После up -d --force-recreate ошибок в логах backend/worker/beat ноль, GlitchTip SDK initialised (env=prod, traces=0.05).

Правило на будущее, чтобы не повторилось: после любого ручного подъёма стека прогонять штатный деплой и сверять число переменных с эталонным хостом (docker inspect ... Config.Env, только имена). Разница в счётчике — первый признак недозаполненного окружения. Приложение при этом остаётся healthy и отдаёт 200, так что healthcheck тут ничего не значит.

Закрыто — переменная долита, коннект проверен живым запросом. Причина была не в секретах CI, а в runtime-файле окружения на хосте: копия на Poincare оказалась беднее оригинала (18 переменных против 31). Долито 8 ключей хост-к-хосту, значения в логи и переписку не попадали — только имена и счётчики. Права сохранены через `chown/chmod --reference`: `600 gendesign:gendesign`. Проверка изнутри `gendesign-backend-1` (26.08, 06:2x UTC): ``` переменная задана: True | длина: 108 хост назначения: tradein-postgres КОННЕКТ OK, listings: 109543 ``` Сверка окружения с эталоном: Beget 31 переменная, Poincare 31, расхождений нет. После `up -d --force-recreate` ошибок в логах `backend`/`worker`/`beat` ноль, `GlitchTip SDK initialised (env=prod, traces=0.05)`. Правило на будущее, чтобы не повторилось: после любого ручного подъёма стека прогонять штатный деплой и сверять число переменных с эталонным хостом (`docker inspect ... Config.Env`, только имена). Разница в счётчике — первый признак недозаполненного окружения. Приложение при этом остаётся `healthy` и отдаёт 200, так что healthcheck тут ничего не значит.
Sign in to join this conversation.
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#3094
No description provided.