tgbot: getUpdates падает 23 раза в сутки, а в логе пустая строка вместо причины #3156

Closed
opened 2026-08-27 18:09:01 +00:00 by bot-backend · 1 comment
Collaborator

Замер на проде (Poincare, контейнер tradein-tgbot, 27.08 18:04 UTC):

  • за 24 часа — 23 срабатывания, за последний час — 14 (частота растёт);
  • ретрай почти всегда чинит с первой попытки, до 3/3 не доходило ни разу → потери сообщений нет, есть задержка.

Сама строка лога:

WARNING app.services.tgbot.client: tg client: getUpdates — network error (попытка 1/3):  — retry через 2s

После двоеточия пусто: str(exc) у сетевых исключений httpx (ReadError, ConnectError, ReadTimeout) обычно пустой, а тип исключения в строку не попадает. Из-за этого отличить таймаут от обрыва TLS от сброса соединения по логу невозможно.

Что уже исключено: сеть до Telegram цела — сырой TLS на 149.154.167.220:443 проходит 6/6 попыток за ~0.16s.

Что сделать

  1. Логировать тип: %s: %s", type(exc).__name__, exc — минимальная правка, без неё дальше диагностировать нечего.
  2. После накопления суток с типами — решать, лечится ли это таймаутами/keep-alive или это внешняя деградация.

Файл: tradein-mvp/backend/app/services/tgbot/client.py.

Замер на проде (Poincare, контейнер `tradein-tgbot`, 27.08 18:04 UTC): - за 24 часа — **23** срабатывания, за последний час — **14** (частота растёт); - ретрай почти всегда чинит с первой попытки, до `3/3` не доходило ни разу → потери сообщений нет, есть задержка. Сама строка лога: ``` WARNING app.services.tgbot.client: tg client: getUpdates — network error (попытка 1/3): — retry через 2s ``` После двоеточия **пусто**: `str(exc)` у сетевых исключений httpx (`ReadError`, `ConnectError`, `ReadTimeout`) обычно пустой, а тип исключения в строку не попадает. Из-за этого отличить таймаут от обрыва TLS от сброса соединения по логу невозможно. Что уже исключено: сеть до Telegram цела — сырой TLS на `149.154.167.220:443` проходит 6/6 попыток за ~0.16s. ## Что сделать 1. Логировать тип: `%s: %s", type(exc).__name__, exc` — минимальная правка, без неё дальше диагностировать нечего. 2. После накопления суток с типами — решать, лечится ли это таймаутами/keep-alive или это внешняя деградация. Файл: `tradein-mvp/backend/app/services/tgbot/client.py`.
Author
Collaborator

Проверено на проде — и свет сразу что-то показал

Контейнер tradein-tgbot пересоздан деплоем в 19:12:39 UTC. Первая же строка нового формата:

2026-08-27 19:15:21,795 WARNING app.services.tgbot.client: tg client: getUpdates — network error (попытка 1/3): ConnectTimeout — retry через 2s

Тип есть, диагностировать теперь есть что.

И он сразу сузил поиск: это ConnectTimeout, а не ReadError. Рвётся не чтение уже установленного соединения, а само его установление — при том, что сырой TLS-хендшейк до 149.154.167.220:443 проходит 6/6 за ~0.16s. Разница существенная: она уводит от «сеть моргает» к обращению по имени и установлению соединения из контейнера — DNS, пул соединений httpx, время жизни keep-alive.

Закрываю: задача была вернуть причину в лог, она вернулась. Продолжение — отдельным тикетом, когда накопятся сутки замеров с типами: сейчас видно одно событие, а решать по одному событию — это ровно то, из-за чего тикет и появился.

## Проверено на проде — и свет сразу что-то показал Контейнер `tradein-tgbot` пересоздан деплоем в 19:12:39 UTC. Первая же строка нового формата: ``` 2026-08-27 19:15:21,795 WARNING app.services.tgbot.client: tg client: getUpdates — network error (попытка 1/3): ConnectTimeout — retry через 2s ``` Тип есть, диагностировать теперь есть что. **И он сразу сузил поиск: это `ConnectTimeout`, а не `ReadError`.** Рвётся не чтение уже установленного соединения, а само его установление — при том, что сырой TLS-хендшейк до `149.154.167.220:443` проходит 6/6 за ~0.16s. Разница существенная: она уводит от «сеть моргает» к обращению по имени и установлению соединения из контейнера — DNS, пул соединений httpx, время жизни keep-alive. Закрываю: задача была вернуть причину в лог, она вернулась. Продолжение — отдельным тикетом, когда накопятся сутки замеров с типами: сейчас видно одно событие, а решать по одному событию — это ровно то, из-за чего тикет и появился.
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#3156
No description provided.