[ВОЛК] коррекция бота под повторные попытки
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/manual/woodpecker Pipeline was successful

This commit is contained in:
2026-01-11 19:05:01 +03:00
parent b0f94c69e2
commit 7c4efdbc8e
+95 -7
View File
@@ -4,6 +4,7 @@ import time
import errno import errno
from dotenv import load_dotenv from dotenv import load_dotenv
import telebot import telebot
from telebot import apihelper
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
import pymysql import pymysql
from datetime import datetime, timezone from datetime import datetime, timezone
@@ -159,6 +160,11 @@ for name, value in required_vars.items():
logger.error(f"Требуется переменная окружения {name}") logger.error(f"Требуется переменная окружения {name}")
exit(1) exit(1)
# Настройка таймаутов для Telegram API
apihelper.READ_TIMEOUT = 120 # Таймаут на чтение ответа (увеличен для больших сообщений)
apihelper.CONNECT_TIMEOUT = 30 # Таймаут на подключение
apihelper.RETRY_ON_TIMEOUT = True # Автоматические повторные попытки при таймауте
# Создаем экземпляр бота # Создаем экземпляр бота
bot = telebot.TeleBot(RESPONDER_BOT_TOKEN) bot = telebot.TeleBot(RESPONDER_BOT_TOKEN)
@@ -802,9 +808,13 @@ def download_image(image_url):
return None return None
def send_post_message(chat_id, text, image_url=None, reply_markup=None): def send_post_message(chat_id, text, image_url=None, reply_markup=None):
"""Отправляет сообщение с изображением или текстом""" """Отправляет сообщение с изображением или текстом с повторными попытками при таймауте"""
logger.info(f"starting send_post_message") logger.info(f"starting send_post_message")
try:
# Параметры для повторных попыток при таймауте
max_retries = 5
retry_interval = 2
# Дополнительная обрезка текста # Дополнительная обрезка текста
if len(text) > UNIFIED_MAX_LENGTH: if len(text) > UNIFIED_MAX_LENGTH:
text = text[:UNIFIED_MAX_LENGTH - 3] + "..." text = text[:UNIFIED_MAX_LENGTH - 3] + "..."
@@ -813,7 +823,9 @@ def send_post_message(chat_id, text, image_url=None, reply_markup=None):
# Загружаем изображение # Загружаем изображение
image = download_image(image_url) image = download_image(image_url)
if image: if image:
# Отправляем фото с подписью # Отправляем фото с подписью с повторными попытками
for attempt in range(1, max_retries + 1):
try:
bot.send_photo( bot.send_photo(
chat_id, chat_id,
photo=image, photo=image,
@@ -821,25 +833,64 @@ def send_post_message(chat_id, text, image_url=None, reply_markup=None):
reply_markup=reply_markup, reply_markup=reply_markup,
parse_mode='HTML' parse_mode='HTML'
) )
logger.info(f"Сообщение с изображением успешно отправлено (попытка {attempt})")
return True return True
except Exception as e:
error_str = str(e)
# Проверяем, является ли это таймаутом
if 'timeout' in error_str.lower() or 'timed out' in error_str.lower():
if attempt < max_retries:
logger.warning(f"Таймаут при отправке фото (попытка {attempt}/{max_retries}), повтор через {retry_interval} сек...")
time.sleep(retry_interval)
continue
else:
logger.error(f"Таймаут при отправке фото после {max_retries} попыток: {e}")
return False
else:
# Для других ошибок не повторяем
logger.error(f"Ошибка отправки фото: {e}")
return False
return False
else: else:
logger.warning(f"Не удалось загрузить изображение: {image_url}") logger.warning(f"Не удалось загрузить изображение: {image_url}")
# Если изображение отсутствует или не загружено, отправляем текст # Если изображение отсутствует или не загружено, отправляем текст с повторными попытками
for attempt in range(1, max_retries + 1):
try:
bot.send_message( bot.send_message(
chat_id, chat_id,
text, text,
reply_markup=reply_markup, reply_markup=reply_markup,
parse_mode='HTML' parse_mode='HTML'
) )
logger.info(f"Текстовое сообщение успешно отправлено (попытка {attempt})")
return True return True
except Exception as e: except Exception as e:
error_str = str(e)
# Проверяем, является ли это таймаутом
if 'timeout' in error_str.lower() or 'timed out' in error_str.lower():
if attempt < max_retries:
logger.warning(f"Таймаут при отправке сообщения (попытка {attempt}/{max_retries}), повтор через {retry_interval} сек...")
time.sleep(retry_interval)
continue
else:
logger.error(f"Таймаут при отправке сообщения после {max_retries} попыток: {e}")
return False
else:
# Для других ошибок не повторяем
logger.error(f"Ошибка отправки сообщения: {e}") logger.error(f"Ошибка отправки сообщения: {e}")
return False return False
return False
def send_direct_message(user_id, message_text): def send_direct_message(user_id, message_text):
"""Отправляет сообщение пользователю по ID с обработкой ошибок""" """Отправляет сообщение пользователю по ID с обработкой ошибок и повторными попытками при таймауте"""
logger.info(f"starting send_direct_message") logger.info(f"starting send_direct_message")
# Параметры для повторных попыток при таймауте
max_retries = 5
retry_interval = 2
try: try:
# Проверяем, что сообщение не пустое # Проверяем, что сообщение не пустое
if not message_text or not message_text.strip(): if not message_text or not message_text.strip():
@@ -848,7 +899,9 @@ def send_direct_message(user_id, message_text):
log_event("error", f"user_{user_id}", message=error_msg) log_event("error", f"user_{user_id}", message=error_msg)
return False, error_msg return False, error_msg
# Отправляем сообщение # Отправляем сообщение с повторными попытками
for attempt in range(1, max_retries + 1):
try:
bot.send_message( bot.send_message(
user_id, user_id,
message_text, message_text,
@@ -857,8 +910,24 @@ def send_direct_message(user_id, message_text):
# Логируем успешную отправку # Логируем успешную отправку
log_event("info", f"user_{user_id}", message=f"Сообщение отправлено: {message_text[:50]}...") log_event("info", f"user_{user_id}", message=f"Сообщение отправлено: {message_text[:50]}...")
logger.info(f"Сообщение успешно отправлено пользователю {user_id}") logger.info(f"Сообщение успешно отправлено пользователю {user_id} (попытка {attempt})")
return True, "Сообщение отправлено успешно" return True, "Сообщение отправлено успешно"
except Exception as e:
error_str = str(e)
# Проверяем, является ли это таймаутом
if 'timeout' in error_str.lower() or 'timed out' in error_str.lower():
if attempt < max_retries:
logger.warning(f"Таймаут при отправке сообщения пользователю {user_id} (попытка {attempt}/{max_retries}), повтор через {retry_interval} сек...")
time.sleep(retry_interval)
continue
else:
error_msg = f"Таймаут при отправке сообщения после {max_retries} попыток: {e}"
logger.error(error_msg)
log_event("error", f"user_{user_id}", message=error_msg)
return False, f"Таймаут при отправке сообщения. Попробуйте позже."
else:
# Для других ошибок выходим из цикла и обрабатываем дальше
break
except telebot.apihelper.ApiTelegramException as e: except telebot.apihelper.ApiTelegramException as e:
error_msg = f"Ошибка Telegram API: {e}" error_msg = f"Ошибка Telegram API: {e}"
@@ -963,12 +1032,31 @@ def handle_start(message):
# Команда /start без параметров # Команда /start без параметров
welcome_text = get_welcome_text() welcome_text = get_welcome_text()
# Отправляем приветственное сообщение с повторными попытками при таймауте
max_retries = 5
retry_interval = 2
for attempt in range(1, max_retries + 1):
try:
bot.send_message( bot.send_message(
message.chat.id, message.chat.id,
welcome_text, welcome_text,
reply_markup=create_main_keyboard(), reply_markup=create_main_keyboard(),
parse_mode='HTML' parse_mode='HTML'
) )
logger.info(f"Приветственное сообщение отправлено (попытка {attempt})")
break
except Exception as e:
error_str = str(e)
if 'timeout' in error_str.lower() or 'timed out' in error_str.lower():
if attempt < max_retries:
logger.warning(f"Таймаут при отправке приветственного сообщения (попытка {attempt}/{max_retries}), повтор через {retry_interval} сек...")
time.sleep(retry_interval)
continue
else:
logger.error(f"Таймаут при отправке приветственного сообщения после {max_retries} попыток: {e}")
raise
else:
raise
except Exception as e: except Exception as e:
error_msg = f"Ошибка в обработке /start: {e}" error_msg = f"Ошибка в обработке /start: {e}"
logger.error(error_msg) logger.error(error_msg)