Система миграций плагинов позволяет плагинам автоматически обновлять схему базы данных и данные при обновлении до более новых версий. Эта система работает аналогично основной системе миграций, но специфична для отдельных плагинов.

Как это работает

  1. Автоматическое обнаружение: При загрузке плагина система автоматически проверяет наличие ожидающих миграций
  2. Отслеживание версий: Версия каждого плагина отслеживается отдельно в базе данных
  3. Файлы миграций: Миграции хранятся в директории migrations/ внутри каждого плагина
  4. Автоматическое выполнение: Миграции автоматически применяются при увеличении версии плагина
  5. Начальные данные сначала: Настройки и метаобъекты создаются из initial_data.py перед запуском миграций
  6. Только изменения данных: Миграции должны фокусироваться на изменении данных, а не на создании элементов схемы
  7. Интеграция с сервисами: PluginMigrationService доступен через services.plugin_migrations как и другие сервисы

Структура файлов

plugins/
├── your_plugin/
│   ├── info.json          # Содержит версию плагина
│   ├── plugin.py          # Основной файл плагина
│   ├── migrations/        # Директория файлов миграций
│   │   ├── __init__.py
│   │   ├── template.py    # Шаблон для новых миграций
│   │   ├── 1_0_1.py       # Миграция для версии 1.0.1
│   │   ├── 1_0_2.py       # Миграция для версии 1.0.2
│   │   └── 2_0_0.py       # Миграция для версии 2.0.0
│   └── ...

Формат файла миграции

Файлы миграций должны называться с использованием номера версии, где точки заменены подчеркиваниями:

  • Версия 1.0.1 → имя файла 1_0_1.py
  • Версия 2.1.0 → имя файла 2_1_0.py

Каждый файл миграции должен содержать функцию up():

def up():
    """
    Код для обновления базы данных плагина до этой версии
    """
    from core.data import storage
    # Пример: Обновление существующего значения настройки
    storage.settings.set('your_plugin_setting', 'new_value')

Создание миграций

Ручное создание

  1. Создайте директорию migrations/ в вашем плагине, если она не существует
  2. Скопируйте шаблон из plugins/example_plugin/migrations/template.py
  3. Переименуйте его в вашу версию (например, 1_0_1.py)
  4. Реализуйте функцию up() с вашей логикой миграции

Начальные данные vs Миграции

Начальные данные (initial_data.py)

  • Назначение: Определение схемы и структуры
  • Когда выполняется: Каждый раз при загрузке плагина
  • Что помещать сюда:
    • Определения настроек (структура, а не значения)
    • Сигнатуры метаобъектов
    • Группы настроек
    • Данные по умолчанию, которые должны всегда существовать

Миграции

  • Назначение: Изменение данных и значений при обновлении версий
  • Когда выполняется: Только при обновлении до новой версии
  • Что помещать сюда:
    • Обновление значений настроек
    • Добавление/удаление записей
    • Преобразования данных
    • Изменения схемы, которые нужно применить один раз

Пример рабочего процесса

  1. Версия 1.0.0: Определите настройки в initial_data.py
  2. Версия 1.0.1: Используйте миграцию для обновления значений настроек
  3. Версия 1.1.0: Добавьте новые настройки в initial_data.py, используйте миграцию для установки их значений

Примеры миграций

Обновление значения настройки

def up():
    from core.data import storage
    # Обновление существующей настройки на новое значение
    storage.settings.set('my_plugin_api_key', 'new_api_key_value')

Добавление данных в метаобъекты

def up():
    from core.data import storage
    # Добавление данных по умолчанию в метаобъект (определенный в initial_data.py)
    storage.metaobjects.create('my_plugin_items', {
        'name': 'Default Item',
        'description': 'Created by migration'
    })

Обновление существующих записей

def up():
    from core.data import storage
    # Обновление существующих записей для добавления нового поля
    existing_records = storage.metaobjects.get_metaobject_data('my_plugin_items')
    for record in existing_records:
        if 'old_field' in record:
            storage.metaobjects.update('my_plugin_items', record['_id'], {
                'new_field': record['old_field'],
                '$unset': {'old_field': 1}
            })

Лучшие практики

  1. Тестируйте миграции перед развертыванием в продакшене
  2. Используйте описательные имена миграций, которые объясняют, что делает миграция
  3. Держите миграции маленькими и сфокусированными — одно логическое изменение на миграцию
  4. Обновляйте версию плагина в info.json при добавлении миграций
  5. Документируйте ваши миграции с четкими комментариями
  6. Не создавайте настройки в миграциях — используйте initial_data.py для этого
  7. Используйте миграции для изменений данных — обновление значений, добавление записей и т.д.
  8. Планируйте миграции тщательно, поскольку откат не поддерживается

Управление версиями

  • Система автоматически отслеживает версию каждого плагина отдельно
  • Миграции применяются в порядке версий (1.0.1, 1.0.2, 2.0.0 и т.д.)
  • Если плагин понижается в версии, система обнаружит это, но не будет автоматически откатывать
  • Примечание: Функциональность отката не поддерживается — миграции только вперед

Устранение неполадок

Миграция не удалась

Если миграция не удалась:

  1. Проверьте логи для получения подробных сообщений об ошибках
  2. Исправьте код миграции
  3. Перезапустите бота для повторной попытки миграции

Несоответствие версий

Если вы видите предупреждения о несоответствии версий:

  1. Проверьте, что ваш info.json имеет правильную версию
  2. Убедитесь, что файлы миграций существуют для всех промежуточных версий
  3. Проверьте логи для получения подробной информации о статусе миграций

Проблемы с базой данных

Если вы столкнулись с проблемами, связанными с базой данных:

  1. Убедитесь, что ваш код миграции использует правильные методы хранилища
  2. Проверьте, что все обязательные поля предоставлены при создании записей
  3. Убедитесь, что ваша миграция не конфликтует с существующими данными