early response to the request

This commit is contained in:
Vladless
2026-02-27 19:40:33 +03:00
parent 2fdcb283eb
commit 5709dca63c
4 changed files with 59 additions and 8 deletions
+18 -4
View File
@@ -38,6 +38,12 @@ _CALLBACK_ANSWER_IGNORE = (
"query id is invalid",
)
_MESSAGE_NOT_MODIFIED = "message is not modified"
def _is_message_not_modified(exc: BaseException) -> bool:
return isinstance(exc, TelegramBadRequest) and _MESSAGE_NOT_MODIFIED in str(exc).lower()
async def safe_answer_callback(callback_query: CallbackQuery, text: str | None = None, show_alert: bool = False, **kwargs) -> None:
"""
@@ -298,7 +304,9 @@ async def edit_or_send_message(
InputMediaAnimation(media=cached_id, caption=text), reply_markup=reply_markup
)
return
except Exception:
except Exception as e:
if _is_message_not_modified(e):
return
try:
if media_type == "photo":
await target_message.answer_photo(
@@ -342,7 +350,9 @@ async def edit_or_send_message(
msg = await target_message.edit_media(
InputMediaAnimation(media=upload, caption=text), reply_markup=reply_markup
)
except Exception:
except Exception as e:
if _is_message_not_modified(e):
return
if media_type == "photo":
msg = await target_message.answer_photo(
photo=upload,
@@ -385,7 +395,9 @@ async def edit_or_send_message(
try:
await target_message.edit_caption(caption=text, reply_markup=reply_markup)
return
except Exception:
except Exception as e:
if _is_message_not_modified(e):
return
pass
try:
await target_message.edit_text(
@@ -394,7 +406,9 @@ async def edit_or_send_message(
disable_web_page_preview=disable_web_page_preview,
)
return
except Exception:
except Exception as e:
if _is_message_not_modified(e):
return
await target_message.answer(
text=text,
reply_markup=reply_markup,
+4 -1
View File
@@ -7,7 +7,7 @@ from middlewares.ban_checker import BanCheckerMiddleware
from middlewares.subscription import SubscriptionMiddleware
from .admin import AdminMiddleware
from .answer import CallbackAnswerMiddleware
from .answer import CallbackAnswerMiddleware, EarlyCallbackAnswerMiddleware
from .concurrency import ConcurrencyLimiterMiddleware
from .direct_start_blocker import DirectStartBlockerMiddleware
from .loggings import LoggingMiddleware
@@ -60,6 +60,9 @@ def register_middleware(
if PROBE_LOGGING:
dispatcher.update.outer_middleware(StreamProbeMiddleware("global"))
# Первым делом отвечаем на callback, чтобы не уйти в «query is too old» при очереди
dispatcher.update.outer_middleware(EarlyCallbackAnswerMiddleware())
if middleware_enabled("runtime_config_sync"):
dispatcher.update.outer_middleware(wrap(RuntimeConfigSyncMiddleware(), "runtime_config_sync"))
if sessionmaker and middleware_enabled("concurrency"):
+36 -2
View File
@@ -1,12 +1,46 @@
from collections.abc import Awaitable, Callable
from typing import Any
from aiogram import BaseMiddleware
from aiogram import BaseMiddleware, Bot
from aiogram.exceptions import TelegramBadRequest
from aiogram.types import CallbackQuery, InaccessibleMessage, TelegramObject
from bot import bot
class EarlyCallbackAnswerMiddleware(BaseMiddleware):
"""
Регистрируется первым в цепочке update. Для CallbackQuery сразу вызывает
answer_callback_query.
"""
async def __call__(
self,
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
event: TelegramObject,
data: dict[str, Any],
) -> Any:
if isinstance(event, CallbackQuery):
bot_instance: Bot | None = data.get("bot")
if bot_instance:
try:
await bot_instance.answer_callback_query(event.id, show_alert=False)
data["callback_answered_early"] = True
except TelegramBadRequest as e:
msg = str(e).lower()
if (
"query is too old" in msg
or "response timeout expired" in msg
or "query id is invalid" in msg
):
pass
else:
raise
except Exception:
pass
return await handler(event, data)
class CallbackAnswerMiddleware(BaseMiddleware):
async def __call__(
self,
@@ -14,7 +48,7 @@ class CallbackAnswerMiddleware(BaseMiddleware):
event: TelegramObject,
data: dict[str, Any],
) -> Any:
if isinstance(event, CallbackQuery) and not data.get("callback_answered_by_concurrency"):
if isinstance(event, CallbackQuery) and not data.get("callback_answered_by_concurrency") and not data.get("callback_answered_early"):
try:
await event.answer()
except Exception:
+1 -1
View File
@@ -33,7 +33,7 @@ class ConcurrencyLimiterMiddleware(BaseMiddleware):
event: TelegramObject,
data: dict[str, Any],
) -> Any:
if isinstance(event, CallbackQuery):
if isinstance(event, CallbackQuery) and not data.get("callback_answered_early"):
bot: Bot | None = data.get("bot")
if bot:
try: