[ВОЛК] коррекция бота под повторные попытки
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
+135 -47
View File
@@ -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] + "..."
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
# Параметры для повторных попыток при таймауте
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:
# Отправляем фото с подписью с повторными попытками
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}")
# Для других ошибок не повторяем
logger.error(f"Ошибка отправки сообщения: {e}")
return False
# Если изображение отсутствует или не загружено, отправляем текст
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
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'
)
# Отправляем сообщение с повторными попытками
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}")
return True, "Сообщение отправлено успешно"
# Логируем успешную отправку
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)