fix: retry Telegram requests on proxy timeouts

This commit is contained in:
MpakobecEx 2026-10-18 18:09:47 +05:00
parent d379be4bbd
commit 83a52bb88e
1 changed files with 53 additions and 15 deletions

68
bot.py
View File

@ -8,7 +8,7 @@ from pathlib import Path
from telegram import InputFile, Update from telegram import InputFile, Update
from telegram.constants import ChatAction, ChatType from telegram.constants import ChatAction, ChatType
from telegram.error import BadRequest, TelegramError from telegram.error import BadRequest, NetworkError, TelegramError, TimedOut
from telegram.ext import ( from telegram.ext import (
Application, Application,
CommandHandler, CommandHandler,
@ -47,11 +47,11 @@ class MpakoBot:
builder = ( builder = (
Application.builder() Application.builder()
.token(self._settings.bot_token) .token(self._settings.bot_token)
.connect_timeout(10) .connect_timeout(20)
.read_timeout(30) .read_timeout(60)
.write_timeout(30) .write_timeout(60)
.get_updates_connect_timeout(10) .get_updates_connect_timeout(20)
.get_updates_read_timeout(30) .get_updates_read_timeout(60)
.post_init(self._post_init) .post_init(self._post_init)
.post_shutdown(self._post_shutdown) .post_shutdown(self._post_shutdown)
) )
@ -251,7 +251,15 @@ class MpakoBot:
await message.reply_text("Не удалось поставить задачу. Попробуй позже.") await message.reply_text("Не удалось поставить задачу. Попробуй позже.")
return False return False
status_message = await message.reply_text(self._ack_text(position)) try:
status_message = await self._retry(
message.reply_text, self._ack_text(position)
)
except TelegramError:
logger.exception(
"Не удалось отправить подтверждение по запросу %s", request.id
)
return True
self._status_messages[request.id] = ( self._status_messages[request.id] = (
status_message.chat_id, status_message.chat_id,
status_message.message_id, status_message.message_id,
@ -303,6 +311,23 @@ class MpakoBot:
event.error or "Не удалось сгенерировать изображение.", event.error or "Не удалось сгенерировать изображение.",
) )
async def _retry(self, func, *args, attempts: int = 3, **kwargs):
delay = 1.0
for attempt in range(1, attempts + 1):
try:
return await func(*args, **kwargs)
except (TimedOut, NetworkError):
if attempt >= attempts:
raise
logger.warning(
"Telegram timeout (%s/%s), повтор через %.0f с",
attempt,
attempts,
delay,
)
await asyncio.sleep(delay)
delay *= 2
async def _edit_status( async def _edit_status(
self, self,
request_id: int, request_id: int,
@ -328,7 +353,8 @@ class MpakoBot:
chat_id, message_id = target chat_id, message_id = target
try: try:
await self._bot.edit_message_text( await self._retry(
self._bot.edit_message_text,
chat_id=chat_id, chat_id=chat_id,
message_id=message_id, message_id=message_id,
text=text, text=text,
@ -366,22 +392,26 @@ class MpakoBot:
await self._finish_failed(request, "Файл результата не читается.") await self._finish_failed(request, "Файл результата не читается.")
return return
try: try:
await self._bot.send_photo( await self._retry(
self._bot.send_photo,
chat_id=chat_id, chat_id=chat_id,
photo=InputFile(content, filename=filename), photo=InputFile(content, filename=filename),
caption=caption, caption=caption,
read_timeout=120, read_timeout=120,
write_timeout=120, write_timeout=120,
attempts=2,
) )
except TelegramError: except TelegramError:
logger.exception("Не удалось отправить фото по запросу %s", request.id) logger.exception("Не удалось отправить фото по запросу %s", request.id)
try: try:
await self._bot.send_document( await self._retry(
self._bot.send_document,
chat_id=chat_id, chat_id=chat_id,
document=InputFile(content, filename=filename), document=InputFile(content, filename=filename),
caption=caption, caption=caption,
read_timeout=120, read_timeout=120,
write_timeout=120, write_timeout=120,
attempts=2,
) )
except TelegramError: except TelegramError:
await self._finish_failed( await self._finish_failed(
@ -397,7 +427,8 @@ class MpakoBot:
text = f"Не получилось: {error}" text = f"Не получилось: {error}"
if target is not None and self._bot is not None: if target is not None and self._bot is not None:
try: try:
await self._bot.edit_message_text( await self._retry(
self._bot.edit_message_text,
chat_id=target[0], chat_id=target[0],
message_id=target[1], message_id=target[1],
text=text, text=text,
@ -406,7 +437,9 @@ class MpakoBot:
logger.debug("Не удалось показать ошибку по запросу %s", request.id) logger.debug("Не удалось показать ошибку по запросу %s", request.id)
if self._bot is not None: if self._bot is not None:
try: try:
await self._bot.send_message(chat_id=chat_id, text=text) await self._retry(
self._bot.send_message, chat_id=chat_id, text=text
)
except TelegramError: except TelegramError:
logger.exception( logger.exception(
"Не удалось отправить ошибку по запросу %s", request.id "Не удалось отправить ошибку по запросу %s", request.id
@ -416,7 +449,9 @@ class MpakoBot:
if self._bot is not None: if self._bot is not None:
try: try:
await self._bot.send_message(chat_id=chat_id, text=text) await self._retry(
self._bot.send_message, chat_id=chat_id, text=text
)
except TelegramError: except TelegramError:
logger.exception("Не удалось отправить ошибку по запросу %s", request.id) logger.exception("Не удалось отправить ошибку по запросу %s", request.id)
@ -425,8 +460,11 @@ class MpakoBot:
self._last_edit.pop(request_id, None) self._last_edit.pop(request_id, None)
if delete and target is not None and self._bot is not None: if delete and target is not None and self._bot is not None:
try: try:
await self._bot.delete_message( await self._retry(
chat_id=target[0], message_id=target[1] self._bot.delete_message,
chat_id=target[0],
message_id=target[1],
attempts=2,
) )
except TelegramError: except TelegramError:
logger.debug("Не удалось удалить статус %s", request_id) logger.debug("Не удалось удалить статус %s", request_id)