Ну що, готові до чергової хвилі фану з базами даних? Сьогодні поговоримо про те, як справлятися з реальним хаосом міграцій у великих проєктах. Ви, мабуть, вже знайомі з міграціями Alembic, адже ми нещодавно тренувалися в створенні, відкаті та оновленні міграцій. Але що робити, якщо на проєкті 5 розробників (або більше), і кожен з них активно копирсається в моделях? Так-так, це саме ті «веселі» моменти, коли одна міграція конфліктує з іншою, і ваш ранок перетворюється на захопливу гру «знайди й виправ проблему».
Перш ніж запропонувати рішення, давайте усвідомимо, з чим доведеться стикнутися:
- Конфлікти міграцій. Уявіть: двоє розробників одночасно створюють міграції для однієї й тієї ж таблиці (наприклад, додають різні стовпці). В результаті їхні зміни не можуть застосуватися послідовно, бо Alembic не розуміє, хто головний.
- Паралельність роботи. У великій команді розробники рухаються швидко: створюють гілки, пишуть код і генерують міграції. В підсумку міграції навіть можуть «забути» про існуючі зміни з інших гілок.
- Порядок застосування. Alembic застосовує міграції в порядку їхніх залежностей, але якщо структура міграцій порушиться (наприклад, через різні мітки часу), база даних може опинитися в непередбачуваному стані.
- Синхронізація між командами. Ви працюєте над однією частиною проєкту, а ваш колега — над іншою, і все це в різних гілках. Дуже легко не помітити «чужі» зміни, поки вони не вмерджилися.
🔧 Методи керування множинними міграціями
1. 🚸 Єдиний процес створення міграцій
Перше правило для великої команди: визначте угоди щодо міграцій. Це може бути набір простих правил:
- Усі зміни в схемах даних документуються і обговорюються заздалегідь. Наприклад, створюється завдання в трекері, де описані зміни.
- Одна людина з команди (або ротаційний DevOps-герой тижня) відповідає за об'єднання міграцій.
- Перед створенням міграції переконайтеся, що база даних синхронізована (виконайте
alembic upgrade head).
2. 🕒 Послідовність міграцій
Коли команда працює над однією й тією ж базою даних, важливо контролювати порядок застосування міграцій. Alembic зберігає метаінформацію про міграції в спеціальній таблиці alembic_version. Кожна міграція має унікальний ідентифікатор (зазвичай це хеш), і Alembic застосовує міграції згідно їхніх залежностей.
Реальна проблема:
припустимо, у нас є міграція 123_add_users_table.py і міграція 456_add_orders_table.py, які створені в різний час. Якщо ми випадково поміняємо їхній порядок у кодовій базі або видалимо залежність, база даних може «з'їхати з глузду».
Як уникнути:
- Переконайтеся, що кожна нова міграція вказує на останню версію (
revisionвказує наparent). - Перевіряйте
alembic historyперед виконаннямupgrade, щоб упевнитися, що порядок коректний.
3. 🤝 Злиття конфліктних міграцій
Коли міграції створюються паралельно в різних гілках, часто виникає ситуація, де обидві міграції мають один і той же батьківський revision. Це призводить до конфлікту дерева міграцій. Здається, проблема нерозв'язна, але ні.
Приклад:
- Міграція
revision_1— спільний пращур. - Розробник A створив
revision_2aз зміною таблиціusers. - Розробник B створив
revision_2bз додаванням таблиціorders.
Коли ми намагаємося об'єднати гілки, Alembic не знає, яку міграцію застосовувати першою.
Рішення: створюємо «об'єднуючу» міграцію. Alembic дозволяє зливати гілки міграцій. Просто створіть новий файл:
alembic revision --head <revision_2a> --head <revision_2b> -m "Merge revisions"
Цей файл збереже порядок міграцій і усуне конфлікт. Тепер у об'єднаної версії буде два «батьківські» revision-и.
4. 🌱 Використання фейкових міграцій (Fake Migrations)
Якщо міграція була застосована до бази даних вручну (наприклад, адміністратором), ви можете позначити її як виконану, щоб уникнути повторного застосування:
alembic stamp head
Ця команда просто оновлює таблицю Alembic, не змінюючи структуру бази даних.
5. 🔄 Керування змінами схеми в активних гілках
Коли робота йде в кількох гілках, синхронізація змін стає складною. Ось що можна зробити:
- Оновлюйтеся регулярно. Після того, як нова міграція з'явилася в головній гілці, переконайтеся, що ваша локальна гілка її застосовує.
- Використовуйте автоматичну генерацію. Якщо ви впевнені, що ваші зміни не конфліктують з іншими, використовуйте
--autogenerate, а потім вручну перевірте файл.
6. 📦 Резервні копії та відкат
У великих проєктах відкат міграції — не дивина. Ви вже знаєте, як використовувати alembic downgrade, але важливо подумати про наслідки. Наприклад, якщо ви видаляєте стовпець, дані з нього зникають. Щоб уникнути катастрофи, робіть резервні копії перед великими змінами.
Для швидкого резервного копіювання PostgreSQL:
pg_dump -U username -W -F c -b -v -f backup_file.sql dbname
🛠️ Практичне застосування
Давайте розглянемо приклад реального сценарію.
У проєкті у нас вже є таблиця users, і двоє розробників одночасно вирішили її змінити:
- Перший додає поле
age. - Другий додає поле
is_admin.
Розробник A створює міграцію:
# revision file: 123_add_age_to_users
op.add_column('users', sa.Column('age', sa.Integer(), nullable=True))
Розробник B створює свою міграцію:
# revision file: 456_add_is_admin_to_users
op.add_column('users', sa.Column('is_admin', sa.Boolean(), nullable=False, server_default='f'))
При спробі об'єднати зміни в main виникає конфлікт. Рішення:
- Спочатку застосовуються обидві міграції в вихідних гілках.
- Створюється об'єднуюча міграція:
alembic revision --head <revision_id_A> --head <revision_id_B> -m "Merge add_age and add_is_admin"
І фінальна версія об'єднаної міграції виглядатиме так:
# merge_add_age_and_is_admin
def upgrade():
pass # no-op since changes were applied separately
def downgrade():
pass # define rollback logic if necessary
🖥️ Автоматизація в CI/CD
Також вкрай важливо автоматизувати перевірку міграцій на CI/CD. Приклад пайплайна:
- Застосування всіх міграцій на тестовій базі.
- Перевірка структури бази через
alembic history. - Виконання відкату і повторне застосування нових міграцій.
Приклад команди для CI:
alembic upgrade head && alembic downgrade base && alembic upgrade head
Це гарантує, що всі міграції працюють коректно.
🧑💻 Типові помилки і як їх уникнути
- Зміна вже існуючих міграцій. Ніколи не редагуйте старі міграції. Якщо потрібно виправити помилку, створіть нову міграцію.
- Пропуск залежностей. Завжди перевіряйте
alembic historyперед створенням нової версії. - Ігнорування порядку міграцій. Це може призвести до порушення цілісності бази даних.
Тепер ви готові керувати міграціями навіть в найскладнішому проєкті.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ