mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-04-11 05:33:36 +00:00
fix(telegram): shorten polling network errors
This commit is contained in:
parent
b9ee236ca1
commit
549e5ea8e2
@ -12,7 +12,7 @@ from typing import Any, Literal
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from telegram import BotCommand, ReactionTypeEmoji, ReplyParameters, Update
|
from telegram import BotCommand, ReactionTypeEmoji, ReplyParameters, Update
|
||||||
from telegram.error import BadRequest, TimedOut
|
from telegram.error import BadRequest, NetworkError, TimedOut
|
||||||
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
||||||
from telegram.request import HTTPXRequest
|
from telegram.request import HTTPXRequest
|
||||||
|
|
||||||
@ -325,7 +325,8 @@ class TelegramChannel(BaseChannel):
|
|||||||
# Start polling (this runs until stopped)
|
# Start polling (this runs until stopped)
|
||||||
await self._app.updater.start_polling(
|
await self._app.updater.start_polling(
|
||||||
allowed_updates=["message"],
|
allowed_updates=["message"],
|
||||||
drop_pending_updates=False # Process pending messages on startup
|
drop_pending_updates=False, # Process pending messages on startup
|
||||||
|
error_callback=self._on_polling_error,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Keep running until stopped
|
# Keep running until stopped
|
||||||
@ -974,14 +975,36 @@ class TelegramChannel(BaseChannel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug("Typing indicator stopped for {}: {}", chat_id, e)
|
logger.debug("Typing indicator stopped for {}: {}", chat_id, e)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _format_telegram_error(exc: Exception) -> str:
|
||||||
|
"""Return a short, readable error summary for logs."""
|
||||||
|
text = str(exc).strip()
|
||||||
|
if text:
|
||||||
|
return text
|
||||||
|
if exc.__cause__ is not None:
|
||||||
|
cause = exc.__cause__
|
||||||
|
cause_text = str(cause).strip()
|
||||||
|
if cause_text:
|
||||||
|
return f"{exc.__class__.__name__} ({cause_text})"
|
||||||
|
return f"{exc.__class__.__name__} ({cause.__class__.__name__})"
|
||||||
|
return exc.__class__.__name__
|
||||||
|
|
||||||
|
def _on_polling_error(self, exc: Exception) -> None:
|
||||||
|
"""Keep long-polling network failures to a single readable line."""
|
||||||
|
summary = self._format_telegram_error(exc)
|
||||||
|
if isinstance(exc, (NetworkError, TimedOut)):
|
||||||
|
logger.warning("Telegram polling network issue: {}", summary)
|
||||||
|
else:
|
||||||
|
logger.error("Telegram polling error: {}", summary)
|
||||||
|
|
||||||
async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
async def _on_error(self, update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
"""Log polling / handler errors instead of silently swallowing them."""
|
"""Log polling / handler errors instead of silently swallowing them."""
|
||||||
from telegram.error import NetworkError, TimedOut
|
summary = self._format_telegram_error(context.error)
|
||||||
|
|
||||||
if isinstance(context.error, (NetworkError, TimedOut)):
|
if isinstance(context.error, (NetworkError, TimedOut)):
|
||||||
logger.warning("Telegram network issue: {}", str(context.error))
|
logger.warning("Telegram network issue: {}", summary)
|
||||||
else:
|
else:
|
||||||
logger.error("Telegram error: {}", context.error)
|
logger.error("Telegram error: {}", summary)
|
||||||
|
|
||||||
def _get_extension(
|
def _get_extension(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -32,8 +32,10 @@ class _FakeHTTPXRequest:
|
|||||||
class _FakeUpdater:
|
class _FakeUpdater:
|
||||||
def __init__(self, on_start_polling) -> None:
|
def __init__(self, on_start_polling) -> None:
|
||||||
self._on_start_polling = on_start_polling
|
self._on_start_polling = on_start_polling
|
||||||
|
self.start_polling_kwargs = None
|
||||||
|
|
||||||
async def start_polling(self, **kwargs) -> None:
|
async def start_polling(self, **kwargs) -> None:
|
||||||
|
self.start_polling_kwargs = kwargs
|
||||||
self._on_start_polling()
|
self._on_start_polling()
|
||||||
|
|
||||||
|
|
||||||
@ -184,6 +186,7 @@ async def test_start_creates_separate_pools_with_proxy(monkeypatch) -> None:
|
|||||||
assert poll_req.kwargs["connection_pool_size"] == 4
|
assert poll_req.kwargs["connection_pool_size"] == 4
|
||||||
assert builder.request_value is api_req
|
assert builder.request_value is api_req
|
||||||
assert builder.get_updates_request_value is poll_req
|
assert builder.get_updates_request_value is poll_req
|
||||||
|
assert callable(app.updater.start_polling_kwargs["error_callback"])
|
||||||
assert any(cmd.command == "status" for cmd in app.bot.commands)
|
assert any(cmd.command == "status" for cmd in app.bot.commands)
|
||||||
assert any(cmd.command == "dream" for cmd in app.bot.commands)
|
assert any(cmd.command == "dream" for cmd in app.bot.commands)
|
||||||
assert any(cmd.command == "dream-log" for cmd in app.bot.commands)
|
assert any(cmd.command == "dream-log" for cmd in app.bot.commands)
|
||||||
@ -307,6 +310,26 @@ async def test_on_error_logs_network_issues_as_warning(monkeypatch) -> None:
|
|||||||
assert recorded == [("warning", "Telegram network issue: proxy disconnected")]
|
assert recorded == [("warning", "Telegram network issue: proxy disconnected")]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_on_error_summarizes_empty_network_error(monkeypatch) -> None:
|
||||||
|
from telegram.error import NetworkError
|
||||||
|
|
||||||
|
channel = TelegramChannel(
|
||||||
|
TelegramConfig(enabled=True, token="123:abc", allow_from=["*"]),
|
||||||
|
MessageBus(),
|
||||||
|
)
|
||||||
|
recorded: list[tuple[str, str]] = []
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"nanobot.channels.telegram.logger.warning",
|
||||||
|
lambda message, error: recorded.append(("warning", message.format(error))),
|
||||||
|
)
|
||||||
|
|
||||||
|
await channel._on_error(object(), SimpleNamespace(error=NetworkError("")))
|
||||||
|
|
||||||
|
assert recorded == [("warning", "Telegram network issue: NetworkError")]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_on_error_keeps_non_network_exceptions_as_error(monkeypatch) -> None:
|
async def test_on_error_keeps_non_network_exceptions_as_error(monkeypatch) -> None:
|
||||||
channel = TelegramChannel(
|
channel = TelegramChannel(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user