Сигналы¶
Сигналы - это события жизненного цикла бота, которые позволяют выполнять код на определённых этапах запуска и остановки. В отличие от обновлений (updates), сигналы генерируются самим фреймворком, а не приходят от API MAX.ru.
Доступные сигналы¶
Сигнал |
Когда вызывается |
|---|---|
|
До начала поллинга. Бот ещё не подключён к API. Здесь фреймворк валидирует граф роутеров, резолвит middleware и переводит роутеры в состояние «запущен». |
|
После подключения бота к API, но до получения первого обновления. Бот уже авторизован, можно отправлять сообщения. |
|
До закрытия соединения с API. Бот ещё активен, можно отправлять прощальные сообщения. |
|
После закрытия соединения. Бот отключён, соединение закрыто. |
Порядок вызова¶
При запуске через LongPolling сигналы вызываются в следующем порядке:
BeforeStartup ← валидация, резолв middleware
↓
бот подключается к API
↓
AfterStartup ← бот готов к работе
↓
... обработка обновлений ...
↓
BeforeShutdown ← бот ещё активен
↓
бот отключается от API
↓
AfterShutdown ← всё завершено
Регистрация обработчиков¶
Обработчики сигналов регистрируются через одноимённые атрибуты роутера или диспетчера.
Можно использовать как декоратор, так и метод handler().
Через декоратор¶
import os
from maxo import Bot, Dispatcher
from maxo.transport.long_polling import LongPolling
dispatcher = Dispatcher()
@dispatcher.after_startup()
async def on_startup(bot: Bot) -> None:
info = bot.state.info
print(f"Бот @{info.username} запущен!")
@dispatcher.before_shutdown()
async def on_shutdown(bot: Bot) -> None:
print("Бот останавливается...")
if __name__ == "__main__":
LongPolling(dispatcher).run(Bot(os.environ["TOKEN"]))
Через метод handler()¶
from maxo import Bot, Dispatcher
async def on_startup(bot: Bot) -> None:
print(f"Бот @{bot.state.info.username} запущен!")
dispatcher = Dispatcher()
dispatcher.after_startup.handler(on_startup)
Сигналы в дочерних роутерах¶
Сигналы поддерживаются не только в Dispatcher, но и в обычных Router.
При запуске фреймворк обходит всё дерево роутеров и вызывает обработчики
сигналов на каждом уровне:
import os
from maxo import Bot, Dispatcher, Router
from maxo.transport.long_polling import LongPolling
router = Router()
@router.after_startup()
async def on_router_startup(bot: Bot) -> None:
print("Роутер готов к работе")
@router.before_shutdown()
async def on_router_shutdown() -> None:
print("Роутер завершает работу")
dispatcher = Dispatcher()
dispatcher.include(router)
if __name__ == "__main__":
LongPolling(dispatcher).run(Bot(os.environ["TOKEN"]))
Типичные сценарии¶
Инициализация ресурсов¶
Открытие соединений к базам данных, кэшам или внешним сервисам:
import redis.asyncio as redis
from maxo import Dispatcher
dispatcher = Dispatcher()
@dispatcher.after_startup()
async def setup_redis() -> None:
pool = redis.ConnectionPool.from_url("redis://localhost")
dispatcher.workflow_data["redis"] = redis.Redis(connection_pool=pool)
@dispatcher.before_shutdown()
async def close_redis() -> None:
r = dispatcher.workflow_data.get("redis")
if r is not None:
await r.aclose()
Уведомление администратора¶
from maxo import Bot, Dispatcher
dispatcher = Dispatcher()
ADMIN_USER_ID = 123456
@dispatcher.after_startup()
async def notify_admin(bot: Bot) -> None:
await bot.send_message(user_id=ADMIN_USER_ID, text="Бот запущен!")
@dispatcher.before_shutdown()
async def notify_admin_shutdown(bot: Bot) -> None:
await bot.send_message(user_id=ADMIN_USER_ID, text="Бот останавливается.")
Внедрение зависимостей (workflow_data)¶
Данные, помещённые в dispatcher.workflow_data в обработчике сигнала,
будут доступны во всех обработчиках обновлений через контекст (Ctx):
from maxo import Dispatcher
from maxo.routing.updates import MessageCreated
dispatcher = Dispatcher()
@dispatcher.after_startup()
async def setup_config() -> None:
dispatcher.workflow_data["admin_ids"] = [123, 456, 789]
@dispatcher.message_created()
async def handler(update: MessageCreated, admin_ids: list[int]) -> None:
if update.message.unsafe_sender.user_id in admin_ids:
await update.answer_text("Привет, админ!")
Отличие от обработчиков обновлений¶
Свойство |
Обработчик обновления |
Обработчик сигнала |
|---|---|---|
Источник события |
API MAX.ru |
Фреймворк |
Вызывается |
При каждом обновлении |
Один раз (при старте / остановке) |
Первый совпавший |
Да, только первый обработчик |
Нет, все зарегистрированные обработчики |
Доступ к |
Всегда |
|