From 2f701311b80268d791a559a4a01afbc04e7251ca Mon Sep 17 00:00:00 2001 From: kislovdm Date: Thu, 9 Apr 2026 14:47:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=A1=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=81=20=D0=B4=D0=B2=D0=BE=D0=B9=D0=BD=D1=8B=D0=BC=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B8=D0=BD=D0=B3=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reverse_bridge.py | 4 +++- src/telegram_api.py | 39 +++++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/reverse_bridge.py b/src/reverse_bridge.py index 5f7810e..94c40b7 100644 --- a/src/reverse_bridge.py +++ b/src/reverse_bridge.py @@ -93,7 +93,9 @@ class TelegramToMaxBridge: if self._health: self._health.mark_telegram_error() logger.exception("Telegram polling loop error") - await asyncio.sleep(2) + # 409 Conflict: где-то еще идет getUpdates (другой инстанс или webhook/второй poller). + # Делаем backoff, чтобы не долбить API. + await asyncio.sleep(10) async def _handle_updates(self, updates: list[dict[str, Any]]) -> None: max_update_id = None diff --git a/src/telegram_api.py b/src/telegram_api.py index 2aa5d47..f13a065 100644 --- a/src/telegram_api.py +++ b/src/telegram_api.py @@ -108,7 +108,19 @@ class TelegramClient: result = data.get("result", []) if not isinstance(result, list): return [] - return [u for u in result if isinstance(u, dict)] + updates = [u for u in result if isinstance(u, dict)] + # Важно: не делаем getUpdates нигде больше (иначе 409 Conflict). + # Наполняем кэш чатов только из этого потока. + for upd in updates: + for container in ("message", "edited_message", "channel_post", "edited_channel_post"): + msg = upd.get(container) + if not isinstance(msg, dict): + continue + chat = msg.get("chat") + if not isinstance(chat, dict): + continue + self._cache_chat(chat) + return updates async def get_file_url(self, file_id: str) -> str: data = await self._request("getFile", {"file_id": file_id}) @@ -131,6 +143,12 @@ class TelegramClient: }, ) + def _cache_chat(self, chat: dict[str, Any]) -> None: + title_value = self._extract_chat_title(chat) + chat_id = chat.get("id") + if title_value and chat_id is not None: + self._chat_title_to_id[self._normalize_title(title_value)] = str(chat_id) + async def _find_chat_id_by_title(self, chat_title: str) -> str | None: normalized = self._normalize_title(chat_title) if not normalized: @@ -139,23 +157,8 @@ class TelegramClient: cached = self._chat_title_to_id.get(normalized) if cached: return cached - - response = await self._request("getUpdates", {"timeout": 0, "limit": 100}) - for update in response.get("result", []): - for container in ("message", "edited_message", "channel_post", "edited_channel_post"): - message = update.get(container) - if not isinstance(message, dict): - continue - chat = message.get("chat") - if not isinstance(chat, dict): - continue - - title_value = self._extract_chat_title(chat) - chat_id = chat.get("id") - if title_value and chat_id is not None: - self._chat_title_to_id[self._normalize_title(title_value)] = str(chat_id) - - return self._chat_title_to_id.get(normalized) + # Не дергаем getUpdates здесь — это вызовет конфликт с polling циклом. + return None @staticmethod def _extract_chat_title(chat: dict[str, Any]) -> str: