Обновление схемы данных без потерь #17
Notifications
Due Date
No due date set.
Blocks
#10 Расширение, оптимизация и миграции Mnesia
EventHub/EventHubBack
Reference: EventHub/EventHubBack#17
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Этап 5. Обновление схемы данных без потерь (пункт 6 задачи)
Цель: внедрить механизм версионирования схемы и процедуру плавающего обновления, позволяющую добавлять/изменять таблицы и поля без остановки всего сервиса и без потери данных.
Шаги:
migresia:migresiaкак зависимость в rebar.config/erlang.mk.migrationsв проекте.infra_mnesia:start/0после проверки существования таблиц вызыватьmigresia:migrate()для применения неприменённых миграций.mnesia:backup("backup_node@host.bak")).migresia.migresiaподдерживает down-миграции) или восстановления из бекапа.archive_managerдолжен приводить поля к актуальному формату (либо хранить мапперы версий). В большинстве случаев, чтение просто игнорирует новые поля, поэтому совместимость сохраняется.Результат: надёжный процесс изменения схемы данных без потерь и незаметного для пользователей простоя.
План выполнения Задачи #17 – Обновление схемы данных без потерь
1. Анализ и цели
После задач #12–#16 база стабильна, но потребуются изменения схемы в будущем.
Цели:
2. Выбор инструмента
Реализуем собственный легковесный механизм миграций:
schema_migrationsхранит историю применённых миграций.priv/migrations/(или настраиваемого пути).up/0иdown/0.infra_mnesia:init_tables/0.3. Детальный план реализации
3.1. Создание модуля
migration_engineФайл:
src/infra/migration_engine.erlAPI:
init_migrations_table()– создаётschema_migrations, если нет.apply_pending()– компилирует и применяет новые миграции.rollback(Version)– откат к указанной версии.status()– список применённых и ожидающих миграций.3.2. Интеграция в
infra_mnesia.erlПосле
create_indices()добавить:3.3. Первая миграция (фиксация текущей схемы)
Создать
priv/migrations/20260401120000_base_schema.erlс пустымиup/0иdown/0.3.4. Процедура плавающего обновления
Скрипт:
scripts/rolling_update.shmnesia:backup("backup.bak").3.5. Откат
down/0реализована:migration_engine:rollback(Version).mnesia:restore(...).3.6. Архивные узлы
4. Тестирование
Тестирование миграций (задача #17)
1. Подготовка окружения
Остановите приложение, если запущено, и очистите данные:
2. Базовая миграция (уже должна быть создана)
Файл
priv/migrations/20260501120000_base_schema.erlс пустымиup/0иdown/0.3. Тестовая миграция
Создайте файл
priv/migrations/20260504150000_test_migration.erlсо следующим содержимым:4. Запуск приложения и проверка
После старта вы увидите в консоли сообщение "Test migration UP applied!".
Теперь в Erlang-консоли проверьте статус миграций:
Ожидается:
5. Откат тестовой миграции
Выполните:
В консоли появится "Test migration DOWN applied!".
Проверьте статус:
Теперь
appliedдолжна содержать только базовую миграцию.6. Завершение
После отката можно снова запустить
migration_engine:apply_pending(), чтобы миграция опять применилась (для повторных тестов).Удалите тестовую миграцию, когда закончите, чтобы она не мешала в будущем.
Инструкция по проверке миграций:
Запустите приложение с чистой базой:
rm -rf Mnesia.* && make shell
В Erlang-консоли:
rr("include/records.hrl").
Проверьте статус до применения:
migration_engine:status().
Ожидается: #{pending => [...], applied => []}
Примените неприменённые миграции:
migration_engine:apply_pending().
В консоли должно появиться "Test migration UP applied!".
Проверьте статус после применения:
migration_engine:status().
Ожидается: #{pending => [], applied => ["20260504150000_test_migration", "20260501120000_base_schema"]}
Проверьте таблицу schema_migrations:
mnesia:dirty_match_object(#schema_migration{_ = '_'}).
Вернет две записи с полями version и applied_at.
Откатите тестовую миграцию:
migration_engine:rollback("20260501120000_base_schema").
В консоли появится "Test migration DOWN applied!".
Проверьте статус после отката:
migration_engine:status().
applied должно содержать только базовую миграцию.
Повторно примените миграции:
migration_engine:apply_pending().
Снова появится "Test migration UP applied!".
Статус вернется к applied = обе миграции.
Таким образом, механизм миграций работает корректно.