🔃 Колбек-функции
Класс BaseModule
предоставляет несколько методов, которые действуют как callback, позволяя вам выполнять пользовательский код в определенные моменты существования модуля. Вы можете переопределить эти методы в своем классе модуля.
def on_init(self):
- Вызывается после завершения инициализации Stage 2 (
self.stage2()
), что означает, что все стандартные обработчики были зарегистрированы, а всеModuleExtensions
были загружены и инициализированы. - Это хорошее место для настройки внутреннего состояния, загрузки данных из источников, не связанных с базой данных, или запуска фоновых задач, которые не зависят напрямую от готовности базы данных.
INFO
Примечание:** Доступность базы данных (
self.db
) не гарантируется на данном этапе, так как настройка базы данных происходит асинхронно. Если вам нужна БД, используйтеon_db_ready
.- Вызывается после завершения инициализации Stage 2 (
async def on_db_ready(self):
- Вызывается после успешной инициализации базы данных модуля (
self.db
) и создания таблиц, определенных вself.db_meta
(если они не существовали). - Это гарантированная точка, в которой вы можете безопасно взаимодействовать с базой данных вашего модуля сразу после запуска.
- Используйте его для таких задач, как загрузка начального состояния из базы данных, выполнение проверки данных при запуске или инициализация компонентов, зависящих от базы данных.
- Вызывается после успешной инициализации базы данных модуля (
def
on_unload(self):
- Вызывается непосредственно до того, как модуль будет полностью выгружен ModuleLoader. Это происходит во время таких операций, как перезагрузка, обновление или деинсталляция модуля.
- Важно: Используйте этот метод, чтобы выполнить все необходимые действия по очистке. Это включает в себя:
- Остановку фоновых задач или циклов asyncio, запущенных модулем.
- Сохранение любого изменчивого состояния на диск или в базу данных.
- Закрытие сетевых соединений или освобождение других ресурсов.
WARNING
Неправильная очистка в
on_unload
может привести к утечке ресурсов (памяти, дескрипторов файлов, сетевых сокетов) или появлению "зомби-задач"**.
Пример использования:
python
# main.py (внутри вашего класса BaseModule)
import asyncio
class MyBackgroundTaskModule(BaseModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._background_task = None
self._some_state = {} # Example state
def on_init(self):
"""Загрузите состояние из файла, возможно, запустите задачу, если DB не нужна."""
self.logger.info("Модуль инициализирован (on_init). Загружаем состояние...")
try:
# Пример: Загрузка состояния из гипотетического файла
# with open("module_state.json", "r") as f:
# self._some_state = json.load(f)
pass # Замените на реальную логику загрузки
except FileNotFoundError:
self.logger.warning("Стейт файл не найден, начинаем заново.")
self._some_state = {'runs': 0}
# Если задача не требует немедленного DB, можно начать здесь
# self._start_task()
async def on_db_ready(self):
"""БД готова, загрузите состояние БД, запустите зависящие от БД задачи."""
self.logger.info("База данных готова (on_db_ready).")
# Пример: Загрузка чего-либо из БД
# async with self.db.session_maker() as session:
# config_value = await session.scalar(...)
# self._some_state['db_config'] = config_value
# Запустите задачу сейчас, если она зависит от БД
self._start_task()
def _start_task(self):
"""Помощник для запуска фоновой задачи."""
if self._background_task is None or self._background_task.done():
self.logger.info("Запуск фоновой задачи...")
self._background_task = asyncio.create_task(self._run_background_job())
else:
self.logger.warning("Задача уже выполняется.")
async def _run_background_job(self):
"""Пример асинхронной задачи."""
try:
while True:
self.logger.info(f"Фоновая задача запущена... Количество запусков: {self._some_state.get('runs', 0)}")
self._some_state['runs'] = self._some_state.get('runs', 0) + 1
# При необходимости получите доступ к self.db здесь (убедитесь, что он готов через on_db_ready).
await asyncio.sleep(60) # Выполнять каждую минуту
except asyncio.CancelledError:
self.logger.info("Фоновое задание отменено")
except Exception as e:
self.logger.error(f"Фоновое задание не выполнено:{e}", exc_info=True)
finally:
self.logger.info("Фоновое задание выполнено")
def on_unload(self):
"""Очистка: Отменить задание, сохранить состояние."""
# 1. Отмена фонового задания
if self._background_task and not self._background_task.done():
self.logger.info("Cancelling background task...")
self._background_task.cancel()
# Хорошей практикой является кратковременное ожидание или обработка завершения задачи.
# но по возможности сохранять on_unload синхронным для простоты во время выключения.
# Для сложной очистки рассмотрите паттерны, включающие asyncio.gather/wait_for
# внутри асинхронного помощника, вызываемого отсюда, если это строго необходимо.
# 2. Сохранить состояние
# try:
# self.logger.info("Сохранение состояния в файл...")
# # with open("module_state.json", "w") as f:
# # json.dump(self._some_state, f)
# except Exception as e:
# self.logger.error(f"Не удалось сохранить состояние: {e}")
self.logger.info("Очистка завершена.")