import traceback from aiogram import Bot, Dispatcher from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError from aiogram.filters import ExceptionTypeFilter from aiogram.types import BufferedInputFile, ErrorEvent from aiogram.utils.markdown import hbold from config import ADMIN_ID from database import async_session_maker from logger import logger def setup_error_handlers(dp: Dispatcher) -> None: @dp.errors(ExceptionTypeFilter(Exception)) async def errors_handler(event: ErrorEvent, bot: Bot) -> bool: if isinstance(event.exception, TelegramForbiddenError): logger.info(f"User {event.update.message.from_user.id} заблокировал бота.") return True if isinstance(event.exception, TelegramBadRequest): error_message = str(event.exception) if ( "query is too old and response timeout expired or query ID is invalid" in error_message or "message can't be deleted for everyone" in error_message or "message to delete not found" in error_message ): try: tb = "".join( traceback.format_exception( type(event.exception), event.exception, event.exception.__traceback__, ) ) logger.warning(f"Показываем стартовое меню из-за TelegramBadRequest: {error_message}") logger.error(f"Traceback:\n{tb}") if ADMIN_ID: if "query is too old and response timeout expired or query ID is invalid" in error_message: caption = ( f"{hbold('TelegramBadRequest: устаревший callback-запрос')}\n\n" "Что произошло:\n" "• Пользователь нажал старую кнопку, или\n" "• Telegram обработал callback уже после истечения таймаута.\n\n" "Описание:\n" "Такое может происходить из-за временной недоступности Telegram или " "нестабильного подключения сервера к API (задержки, потери пакетов, очереди запросов).\n\n" "Действия:\n" "• Проверить стабильность интернет-соединения сервера.\n" "• Оценить задержки/нагрузку на бота и частоту callback-запросов.\n" "• При необходимости оптимизировать обработку или уменьшить время между нажатием кнопки и ответом." ) else: caption = f"{hbold(type(event.exception).__name__)}: {error_message[:1021]}..." for admin_id in ADMIN_ID: await bot.send_document( chat_id=admin_id, document=BufferedInputFile( tb.encode(), filename=f"error_{event.update.update_id}.txt", ), caption=caption[:1024], ) except Exception as e: logger.error(f"Сбой при логировании/отправке ошибки админу: {e}", exc_info=True) try: from handlers.start import start_entry if event.update.message: fsm_context = dp.fsm.get_context( bot=bot, chat_id=event.update.message.chat.id, user_id=event.update.message.from_user.id, ) async with async_session_maker() as session: await start_entry( event=event.update.message, state=fsm_context, session=session, admin=False, captcha=False, ) elif event.update.callback_query: fsm_context = dp.fsm.get_context( bot=bot, chat_id=event.update.callback_query.message.chat.id, user_id=event.update.callback_query.from_user.id, ) async with async_session_maker() as session: await start_entry( event=event.update.callback_query, state=fsm_context, session=session, admin=False, captcha=False, ) except Exception as e: logger.error(f"Ошибка при показе стартового меню после ошибки: {e}", exc_info=True) return True logger.exception(f"Update: {event.update}\nException: {event.exception}") if not ADMIN_ID: return True try: for admin_id in ADMIN_ID: await bot.send_document( chat_id=admin_id, document=BufferedInputFile( traceback.format_exc().encode(), filename=f"error_{event.update.update_id}.txt", ), caption=f"{hbold(type(event.exception).__name__)}: {str(event.exception)[:1021]}...", ) from handlers.start import start_entry if event.update.message: fsm_context = dp.fsm.get_context( bot=bot, chat_id=event.update.message.chat.id, user_id=event.update.message.from_user.id, ) async with async_session_maker() as session: await start_entry( event=event.update.message, state=fsm_context, session=session, admin=False, captcha=False, ) elif event.update.callback_query: fsm_context = dp.fsm.get_context( bot=bot, chat_id=event.update.callback_query.message.chat.id, user_id=event.update.callback_query.from_user.id, ) async with async_session_maker() as session: await start_entry( event=event.update.callback_query, state=fsm_context, session=session, admin=False, captcha=False, ) except TelegramBadRequest as exception: logger.warning(f"Не удалось отправить детали ошибки: {exception}") except Exception as exception: logger.error(f"Неожиданная ошибка в error handler: {exception}") return True