From 7c4efdbc8e0f7e096221ae1fdcc405e7f799bae8 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Sun, 11 Jan 2026 19:05:01 +0300 Subject: [PATCH] =?UTF-8?q?[=D0=92=D0=9E=D0=9B=D0=9A]=20=D0=BA=D0=BE=D1=80?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=86=D0=B8=D1=8F=20=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tg_mainbot.py | 186 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 137 insertions(+), 49 deletions(-) diff --git a/tg_mainbot.py b/tg_mainbot.py index 862b08f..3f96311 100644 --- a/tg_mainbot.py +++ b/tg_mainbot.py @@ -4,6 +4,7 @@ import time import errno from dotenv import load_dotenv import telebot +from telebot import apihelper from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton import pymysql from datetime import datetime, timezone @@ -159,6 +160,11 @@ for name, value in required_vars.items(): logger.error(f"Требуется переменная окружения {name}") exit(1) +# Настройка таймаутов для Telegram API +apihelper.READ_TIMEOUT = 120 # Таймаут на чтение ответа (увеличен для больших сообщений) +apihelper.CONNECT_TIMEOUT = 30 # Таймаут на подключение +apihelper.RETRY_ON_TIMEOUT = True # Автоматические повторные попытки при таймауте + # Создаем экземпляр бота bot = telebot.TeleBot(RESPONDER_BOT_TOKEN) @@ -802,44 +808,89 @@ def download_image(image_url): return None def send_post_message(chat_id, text, image_url=None, reply_markup=None): - """Отправляет сообщение с изображением или текстом""" + """Отправляет сообщение с изображением или текстом с повторными попытками при таймауте""" logger.info(f"starting send_post_message") - try: - # Дополнительная обрезка текста - if len(text) > UNIFIED_MAX_LENGTH: - text = text[:UNIFIED_MAX_LENGTH - 3] + "..." + + # Параметры для повторных попыток при таймауте + max_retries = 5 + retry_interval = 2 + + # Дополнительная обрезка текста + if len(text) > UNIFIED_MAX_LENGTH: + text = text[:UNIFIED_MAX_LENGTH - 3] + "..." - if image_url: - # Загружаем изображение - image = download_image(image_url) - if image: - # Отправляем фото с подписью - bot.send_photo( - chat_id, - photo=image, - caption=text, - reply_markup=reply_markup, - parse_mode='HTML' - ) - return True + if image_url: + # Загружаем изображение + image = download_image(image_url) + if image: + # Отправляем фото с подписью с повторными попытками + for attempt in range(1, max_retries + 1): + try: + bot.send_photo( + chat_id, + photo=image, + caption=text, + reply_markup=reply_markup, + parse_mode='HTML' + ) + logger.info(f"Сообщение с изображением успешно отправлено (попытка {attempt})") + 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: + logger.warning(f"Не удалось загрузить изображение: {image_url}") + + # Если изображение отсутствует или не загружено, отправляем текст с повторными попытками + for attempt in range(1, max_retries + 1): + try: + bot.send_message( + chat_id, + text, + reply_markup=reply_markup, + parse_mode='HTML' + ) + logger.info(f"Текстовое сообщение успешно отправлено (попытка {attempt})") + 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.warning(f"Не удалось загрузить изображение: {image_url}") - - # Если изображение отсутствует или не загружено, отправляем текст - bot.send_message( - chat_id, - text, - reply_markup=reply_markup, - parse_mode='HTML' - ) - return True - except Exception as e: - logger.error(f"Ошибка отправки сообщения: {e}") - return False + # Для других ошибок не повторяем + logger.error(f"Ошибка отправки сообщения: {e}") + return False + + return False def send_direct_message(user_id, message_text): - """Отправляет сообщение пользователю по ID с обработкой ошибок""" + """Отправляет сообщение пользователю по ID с обработкой ошибок и повторными попытками при таймауте""" logger.info(f"starting send_direct_message") + + # Параметры для повторных попыток при таймауте + max_retries = 5 + retry_interval = 2 + try: # Проверяем, что сообщение не пустое if not message_text or not message_text.strip(): @@ -848,17 +899,35 @@ def send_direct_message(user_id, message_text): log_event("error", f"user_{user_id}", message=error_msg) return False, error_msg - # Отправляем сообщение - bot.send_message( - user_id, - message_text, - parse_mode='HTML' - ) - - # Логируем успешную отправку - log_event("info", f"user_{user_id}", message=f"Сообщение отправлено: {message_text[:50]}...") - logger.info(f"Сообщение успешно отправлено пользователю {user_id}") - return True, "Сообщение отправлено успешно" + # Отправляем сообщение с повторными попытками + for attempt in range(1, max_retries + 1): + try: + bot.send_message( + user_id, + message_text, + parse_mode='HTML' + ) + + # Логируем успешную отправку + log_event("info", f"user_{user_id}", message=f"Сообщение отправлено: {message_text[:50]}...") + logger.info(f"Сообщение успешно отправлено пользователю {user_id} (попытка {attempt})") + 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: error_msg = f"Ошибка Telegram API: {e}" @@ -963,12 +1032,31 @@ def handle_start(message): # Команда /start без параметров welcome_text = get_welcome_text() - bot.send_message( - message.chat.id, - welcome_text, - reply_markup=create_main_keyboard(), - parse_mode='HTML' - ) + # Отправляем приветственное сообщение с повторными попытками при таймауте + max_retries = 5 + retry_interval = 2 + for attempt in range(1, max_retries + 1): + try: + bot.send_message( + message.chat.id, + welcome_text, + reply_markup=create_main_keyboard(), + 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: error_msg = f"Ошибка в обработке /start: {e}" logger.error(error_msg)