null

InconsistentMigrationHistory в Open edX: частая ошибка, редкая причина

Описание проблемы

На предпродовой площадке с edx-platform при попытке вывести список миграций:

manage-lms showmigrations

получаем ошибку вида:

django.db.migrations.exceptions.InconsistentMigrationHistory:
Migration consent.0001_initial is applied before its dependency enterprise.0001_squashed_0092_auto_20200312_1650 on database 'student_module_history'

Ну и далее все попытки манипуляций с миграциями обречены.

Почему так?

student_module_history - это дополнительная база, предусмотренная специально для одной таблицы: coursewarehistoryextended. Здесь хранится история всех ответов. Таблица может быть катастрофически большой, потому и вынесена в отдельную базу. Данные всех остальных приложений хранятся в основной базе: default.

По всей видимости, кто-то когда-то "накатил" на эту дополнительную базу все имеющиеся миграции с ключом --fake. При последующих обновлениях никто эту базу больше не трогал, и за несколько релизов произошло следующее:

  • появлялись новые файлы миграций
  • некоторые миграции были схлопнуты (Squashing migrations)
  • старые файлы миграции заменены одной схлопнутой

В итоге, последовательность миграций была нарушена, о чём предупреждает документация. Мы не можем накатить новые миграции, т.к. они частично отсутствуют в текущей версии, а команда migrate сваливается с ошибкой, показанной выше.

 

Что делать?

Т.к. дело касается предпродовой площадки, применить совет №1 из интернета - DROP DATABASE - не вариант.

Первой в голову пришла идея временно поставить старые версии приложений, в которых присутствуют все файлы миграций - и схлопнутые и оригинальные - и снова фейково накатить всё. Затея с треском провалилась - команда стала падать с новой ошибкой: table django_content_type doesn't exists, вероятно из-за отсутствия других служебных таблиц django, ведь они тоже накатывались фейково.

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

Команда migrate всё ещё не работает, так что придётся удалить лишние строки напрямую из базы. Лишние - это все, которые не относятся к приложению coursewarehistoryextended.

Критически важно подключиться к правильной базе! Иначе - прощай история реальных миграций. Ну и неплохо бы иметь бэкап.
MariaDB [(none)]> connect edxapp_csmh;
MariaDB [edxapp_csmh]> delete from django_migrations where app <> 'coursewarehistoryextended';
Query OK, 947 rows affected (0.009 sec)

MariaDB [edxapp_csmh]> select * from django_migrations;
+-----+---------------------------+--------------------------------+----------------------------+
| id  | app                       | name                           | applied                    |
+-----+---------------------------+--------------------------------+----------------------------+
| 353 | coursewarehistoryextended | 0001_initial                   | 2019-02-01 20:53:06.442139 |
| 354 | coursewarehistoryextended | 0002_force_studentmodule_index | 2019-02-01 20:53:06.511859 |
+-----+---------------------------+--------------------------------+----------------------------+
2 rows in set (0.000 sec)

Таким образом, мы удалили все записи о миграциях, кроме двух действительных. Команда migrate снова работает.

Заключение

Виновник проблемы - тот, кто изначально решил вручную фейково накатить на дополнительную базу все миграции, примерно такой командой: django-admin migrate -d student_module_history --fake

Теперь стало очевидно, что это он сделал зря. В edx-platform ситуацию с несколькими базами должен автоматически разруливать Database Router, который реализован здесь.

Next