|
| 1 | +# Migration Dependency Patterns |
| 2 | + |
| 3 | +## Migration Graph Structure |
| 4 | + |
| 5 | +The `aap_gateway_api` migration graph is not strictly linear. Starting at |
| 6 | +migration 0017, the graph forks into two branches that converge at 0023: |
| 7 | + |
| 8 | +``` |
| 9 | +0017 → 0018 → 0019 → 0020 → 0021 ─┐ |
| 10 | + └──→ 0022 ─────────────────────────┴──→ 0023 (convergence, single leaf) |
| 11 | +``` |
| 12 | + |
| 13 | +This is intentional. Django's migration system is a directed acyclic graph |
| 14 | +(DAG), not a linear sequence. File numbers are cosmetic — execution order is |
| 15 | +determined by the `dependencies` attribute in each migration class. |
| 16 | + |
| 17 | +## Why the Fork Exists |
| 18 | + |
| 19 | +Migration 0022 (`UserSessionMembership`) creates a new table that only |
| 20 | +references `User` and `Session` — neither of which is modified by migrations |
| 21 | +0018–0021. Its declared dependency on 0017 reflects this true schema |
| 22 | +dependency, not the conventional "chain off the latest migration" pattern |
| 23 | +that `makemigrations` produces by default. |
| 24 | + |
| 25 | +This restructuring enables clean backporting of 0022 to stable branches |
| 26 | +where migrations 0018–0021 do not exist (e.g., stable-2.6 stops at 0017). |
| 27 | + |
| 28 | +## Convergence Migration (0023) |
| 29 | + |
| 30 | +Migration `0023_merge_0021_0022` is an empty migration (`operations = []`) |
| 31 | +that depends on both 0021 and 0022. Its purpose is to rejoin the two |
| 32 | +branches into a single leaf node, which Django requires before |
| 33 | +`makemigrations` will create new migrations. |
| 34 | + |
| 35 | +The data cleanup previously performed by 0023 (removing console ServiceType |
| 36 | +and RED_HAT_CONSOLE_URL preference) is handled by the `post_migrate` signal |
| 37 | +handler `remove_console_service_type()` in `preloaded_data.py`. |
| 38 | + |
| 39 | +## Rules for Future Backportable Migrations |
| 40 | + |
| 41 | +When writing a migration that may need backporting to a stable branch: |
| 42 | + |
| 43 | +1. Set `dependencies` to the earliest migration that the operations genuinely |
| 44 | + depend on — not just the latest migration on the branch. |
| 45 | + |
| 46 | +2. Cherry-pick the migration file unmodified to the target stable branch. |
| 47 | + The dependency must be satisfied on that branch. |
| 48 | + |
| 49 | +3. Forward-propagation: a migration backported to an older stable branch |
| 50 | + must also be present on all intermediate stable branches before those |
| 51 | + branches release. This prevents orphan `django_migrations` records on |
| 52 | + upgrade. |
| 53 | + |
| 54 | +4. Add an empty convergence migration on devel (and downstream-only |
| 55 | + convergence migrations on stable branches if needed) to rejoin the |
| 56 | + graph into a single leaf. |
| 57 | + |
| 58 | +5. All future migrations on devel depend on the convergence migration, |
| 59 | + maintaining a single leaf. |
| 60 | + |
| 61 | +## What NOT to Do |
| 62 | + |
| 63 | +- Do not use `migrate --prune` during upgrades. Without forward-propagation, |
| 64 | + `--prune` can delete `django_migrations` records for migrations whose |
| 65 | + files are missing on the target branch. On a subsequent upgrade to a |
| 66 | + release that includes those migrations, Django will attempt to re-apply |
| 67 | + them (e.g., `CREATE TABLE` on an existing table), causing a crash. |
| 68 | + |
| 69 | +- Do not renumber migrations on stable branches. The same migration file |
| 70 | + (same name, same content) should exist on every branch where it's needed. |
| 71 | + |
| 72 | +- Do not create branch-specific migration files with different names for |
| 73 | + the same schema change. This creates divergent `django_migrations` records |
| 74 | + that cannot be reconciled on upgrade. |
| 75 | + |
| 76 | +## References |
| 77 | + |
| 78 | +- AAP-82458: Migration re-parent and converge plan |
| 79 | +- AAP-80663: Full analysis of migrations 0017–0023 with dependency mapping |
| 80 | +- AAP-80375: Investigation of out-of-sync migration in stable-2.6 |
0 commit comments