Migrations sûres
- Leçon 11
- 50 min
- Module 4 : Mettre en production les changements d'IA et de base de données
Leçon 11 sur 15 · CI/CD, tests et mises en production sûresMigrations sûres
1. Comprendre le chemin de livraison
2. Créer un pipeline CI reproductible
3. Gérer les environnements et les secrets
4. Mettre en production les changements d'IA et de base de données
5. Rétablir et maintenir le processus de mise en production
Ce que vous saurez faire
À chaque déploiement, l’ancienne et la nouvelle version fonctionnent en même temps, avec la même base de données. Cette leçon modifie la base de données pour que les deux continuent de fonctionner. Ajoutez d’abord, retirez plus tard. Exécutez chaque changement une seule fois, dans l’ordre, avant le démarrage de la nouvelle version.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- La table d’historique dans PostgreSQL et Compose avec
apietdb, présentés dans Données persistantes : ajouter l’historique du cours L’essentiel de Docker et du nuage pour les développeurs en IA. - Les changements d’API qui rendent les clients incompatibles, présentés dans Conception des ressources et des points de terminaison : règle 3 : une version dans le chemin du cours Créer et déployer votre première API.
- Les environnements locaux (
deploy/local/compose.yaml,scripts/promote-local.sh, port 8082 pour la production) et les lignes de plateforme, présentés dans Promouvoir en préproduction : le parcours local et L’image qui ne démarrait pas sur un Mac. - L’indicateur
CLASSIFIER_VERSIONet la barrière, présentés dans Barrière d’évaluation de l’IA : exemple détaillé : keywords-1.1 derrière un indicateur et La barrière dans la CI.
Ce qu’il vous faut sur votre ordinateur
- Votre dépôt avec keywords-1.1 et la barrière fusionnés dans
main, provenant de Barrière d’évaluation de l’IA : exercice guidé. - L’environnement de production local, avec son
.env(POSTGRES_PASSWORD) etsecrets/production_api_key.txt, provenant de Séparer la configuration : exercice guidé : les fichiers d’environnement local et Promouvoir en préproduction : exercice guidé : promouvoir votre propre empreinte. Docker Desktop doit être en marche. - Si votre projet est absent ou ne fonctionne plus, copiez l’instantané
end-of-m03et refaites l’exercice guidé de la leçon précédente.
Exécuté avec GitHub Actions (ubuntu-24.04, PostgreSQL 18.6 comme conteneur de service) dans Nextia-Intelligence/ticket-api-ci. Aussi exécuté avec Docker Desktop 4.81.0 sur macOS (Apple silicon) et postgres:18.6-trixie. Les étapes pour Windows et Linux n’ont pas été testées.
Le changement : score à côté de confidence
Section intitulée « Le changement : score à côté de confidence »La version 1.2.0 renomme un champ. Chaque classification a un champ confidence (confiance), un nombre de 0 à 1. Ce nom laisse croire aux clients qu’il s’agit d’une probabilité. Ce n’est pas le cas : il mesure la force de correspondance des mots-clés. L’équipe veut le nom neutre score.
L’API est la partie facile. La base de données est plus difficile. La table classifications a une colonne confidence, et deux versions de l’application l’utilisent en même temps :
- Pendant le déploiement, Container Apps démarre la nouvelle révision à côté de l’ancienne. Les deux répondent aux requêtes pendant un moment (Configuration opérationnelle du cours L’essentiel de Docker et du nuage pour les développeurs en IA).
- Lors d’un déploiement canari (Mise en production progressive), les deux fonctionnent volontairement pendant des heures.
- Après un retour en arrière, l’ancienne version fonctionne de nouveau avec la base de données modifiée par la nouvelle version.
La base de données doit donc fonctionner avec les deux versions en tout temps. Faites une prédiction : Amira peut modifier la table de deux façons. Laquelle empêche la version 1.1.0 de fonctionner?
ALTER TABLE classifications RENAME COLUMN confidence TO score;ALTER TABLE classifications ADD COLUMN IF NOT EXISTS score real;L’option A empêche immédiatement 1.1.0 de fonctionner. Son code écrit et lit confidence, mais cette colonne n’existe plus. L’erreur courante à la fin de cette leçon montre les erreurs réelles. L’option B ne brise rien. La version 1.1.0 ne connaît pas score, donc elle ignore la nouvelle colonne. La version 1.2.0 écrit dans les deux.
Ajouter maintenant, retirer plus tard
Section intitulée « Ajouter maintenant, retirer plus tard »L’option B est la première moitié d’une méthode appelée expansion et contraction :
- Ajouter : ajoutez le nouvel élément à côté de l’ancien. L’ancienne et la nouvelle version fonctionnent toutes les deux.
- Passer au nouveau champ : la nouvelle version écrit dans les deux champs. Les clients passent de
confidenceàscoreà leur rythme. L’API marqueconfidencecomme obsolète : il fonctionne encore, mais disparaîtra dans une version annoncée. - Remplir les données existantes : remplissez la nouvelle colonne pour les anciennes lignes. Ce remplissage modifie les données, pas la structure :
UPDATE … SET score = confidence WHERE score IS NULL. - Retirer : retirez l’ancien élément dans une mise en production ultérieure, quand plus rien ne l’utilise. Ici, c’est la version 2.0, une version majeure, car retirer un champ rend les clients incompatibles.
Chaque étape correspond à une mise en production distincte. Entre deux étapes, vous pouvez arrêter, attendre plusieurs jours ou revenir en arrière.
Description textuelle du diagramme
Lisez le tableau par colonne. À chaque étape, au moins la version précédente et la version suivante fonctionnent. Le déploiement peut donc les faire fonctionner ensemble. La version 1.2.x échoue avant l’étape 2. La migration doit donc s’exécuter avant le démarrage de 1.2.0. La version 1.1.0 échoue seulement après l’étape 5. Le retrait attend donc qu’aucune version 1.1.0 ne fonctionne et qu’aucun client ne lise confidence. Remarquez la cellule de 1.2.x à l’étape 3. La version 1.1.0 écrit encore des lignes sans score, et 1.2.x doit aussi fonctionner avec ces lignes. Un retour à 1.1.0 reste possible jusqu’à l’étape 5, car chaque étape précédente fait seulement des ajouts.
Migrations : des fichiers numérotés, appliqués une seule fois
Section intitulée « Migrations : des fichiers numérotés, appliqués une seule fois »Jusqu’ici, l’application créait sa propre table au démarrage (CREATE TABLE IF NOT EXISTS, présenté dans le cours sur Docker). Cela fonctionne pour une table qui ne change jamais. Cela ne permet pas d’ajouter une colonne à une table existante. Cela n’indique pas non plus les changements déjà appliqués à une base de données.
Une migration est un changement numéroté de la structure ou des données d’une base de données, dans un fichier. La version 1.2.0 en a deux :
-- The table that C18 made at start-up. IF NOT EXISTS: a database from C18-- already has it, and this migration then only records that it is there.CREATE TABLE IF NOT EXISTS classifications ( id bigserial PRIMARY KEY, request_id text NOT NULL, category text NOT NULL, priority smallint NOT NULL, confidence real NOT NULL, model_version text NOT NULL, created_at timestamptz NOT NULL DEFAULT now());-- Expand: add the new column next to the old one. It may be empty, because-- version 1.1.0 of the app still writes rows without it during the rollout.ALTER TABLE classifications ADD COLUMN IF NOT EXISTS score real;001 décrit la table qui existe aujourd’hui. Une base de données du cours sur Docker l’a déjà. IF NOT EXISTS rend la migration sûre dans ce cas : elle enregistre la table sans rien changer. 002 n’a pas de NOT NULL. C’est volontaire : 1.1.0 insère des lignes sans score, et une colonne NOT NULL les refuserait.
L’exécuteur de migrations, ticket_api/migrate.py, les applique. Il garde la liste des migrations appliquées dans sa propre table, schema_migrations. Le cœur tient en 10 lignes :
def pending(conn: psycopg.Connection) -> tuple[list[Path], set[str]]: conn.execute(CREATE_LOG) applied = {row[0] for row in conn.execute("SELECT version FROM schema_migrations")} files = sorted(MIGRATIONS.glob("*.sql")) return [f for f in files if f.stem not in applied], applied
# in main(): for f in todo: with conn.transaction(): conn.execute(f.read_text(encoding="utf-8")) conn.execute("INSERT INTO schema_migrations (version) VALUES (%s)", (f.stem,)) print(f"applied {f.stem}")Ces lignes contiennent trois règles. Les fichiers s’exécutent dans l’ordre de leurs noms. Le numéro au début détermine donc l’ordre. Un fichier dans schema_migrations ne s’exécute jamais de nouveau. Chaque fichier s’exécute dans sa propre transaction, avec la ligne qui l’enregistre : soit tout se réalise, soit rien. Le fichier complet se trouve dans ticket_api/migrate.py à c3c7135. Plusieurs équipes utilisent un outil comme Alembic ou Flyway pour cela. L’idée reste la même : des fichiers numérotés, une table des versions appliquées et une transaction par fichier.
Exemple détaillé : migrer une base de données du cours sur Docker
Section intitulée « Exemple détaillé : migrer une base de données du cours sur Docker »Amira teste l’exécuteur sur une copie d’une base de données du cours sur Docker. Elle contient la table créée par l’application et une ligne de la version 1.1.0. Elle demande d’abord ce qui reste à appliquer :
python -m ticket_api.migrate --statusLa sortie (simulée) :
pending 001_create_classificationspending 002_add_scoreElle applique ensuite les migrations, puis exécute de nouveau la même commande :
python -m ticket_api.migratepython -m ticket_api.migrateLa sortie (simulée) :
applied 001_create_classificationsapplied 002_add_scoreDatabase is up to date (2 migrations).Database is up to date (2 migrations).La deuxième exécution n’a rien appliqué. Un pipeline a besoin d’un exécuteur qui peut s’exécuter deux fois sans causer de problèmes. Chaque déploiement l’exécute, et la plupart n’ont rien à appliquer. La table a maintenant la nouvelle colonne, et l’ancienne ligne n’a pas de score :
id | request_id | model_version | confidence | score----+--------------+---------------+------------+------- 1 | c18row000001 | keywords-1.0 | 0.9 |SELECT version FROM schema_migrations énumère 001_create_classifications et 002_add_score, chacune avec l’heure de son application.
Migrer d’abord, puis démarrer la nouvelle version
Section intitulée « Migrer d’abord, puis démarrer la nouvelle version »La nouvelle version a besoin de score. La migration doit donc se terminer avant le démarrage de cette version. Amira intègre cet ordre au déploiement, plutôt que d’en faire une étape qu’une personne doit se rappeler.
L’image contient ses migrations. Une ligne du Dockerfile les copie. L’image de 1.2.0 peut ainsi migrer sa propre base de données : COPY migrations ./migrations.
Compose les exécute d’abord. Un service migrate utilise la même image, lance l’exécuteur, puis se termine. Le service api démarre seulement après sa fin sans erreur :
services: api: # ... depends_on: migrate: condition: service_completed_successfully
migrate: image: ${IMAGE} platform: linux/amd64 command: ["python", "-m", "ticket_api.migrate"] environment: DATABASE_URL: postgresql://tickets:${POSTGRES_PASSWORD}@db:5432/tickets depends_on: db: condition: service_healthySi une migration échoue, migrate se termine avec le code de sortie 1, et api ne démarre pas. L’ancienne version continue de fonctionner. Ajoutez le même service migrate à compose.yaml pour votre ordinateur. La ligne platform vient de Promouvoir en préproduction : l’image qui ne démarrait pas sur un Mac. Le dépôt de référence l’a ajoutée à migrate dans la demande de tirage no 6, après 1.2.0.
L’application cesse de créer la table. Dans main.py, l’appel à history.setup() disparaît. La table créée au démarrage et celle créée par les migrations ne peuvent pas toutes deux servir de référence.
La CI teste les migrations. La tâche de vérification reçoit un conteneur de service PostgreSQL 18.6. GitHub Actions démarre cette base de données à côté de la tâche, puis la supprime après celle-ci. Deux nouveaux tests exécutent les migrations deux fois et enregistrent une classification :
services: postgres: image: postgres:18.6-trixie env: POSTGRES_USER: tickets POSTGRES_PASSWORD: ci-only-not-secret POSTGRES_DB: tickets ports: ["5432:5432"] options: >- --health-cmd "pg_isready -U tickets -d tickets" --health-interval 2s --health-timeout 3s --health-retries 15 # ... - name: Unit, contract and database tests env: TEST_DATABASE_URL: postgresql://tickets:ci-only-not-secret@localhost:5432/tickets run: python -m pytest --junitxml=reports/junit.xmlLe mot de passe n’est pas un secret : la base de données existe seulement pendant les quelques secondes de la tâche. Les tests s’ignorent quand TEST_DATABASE_URL n’est pas défini. Ainsi, pytest fonctionne encore sur un ordinateur sans base de données. Dans la demande de tirage no 5, de feature/score-field vers main, l’exécution 37667028262 a recueilli 30 tests. Ils ont tous réussi en 0,51 seconde.
L’API conserve les deux champs. models.py reçoit score et marque confidence comme obsolète dans le contrat. routes.py leur attribue la même valeur :
confidence: float = Field( ge=0, le=1, description="Deprecated: use score. The same value. Removed in version 2.0.", json_schema_extra={"deprecated": True}, ) score: float = Field(ge=0, le=1, description="How sure the classifier is, from 0 to 1.")La version devient 1.2.0 : le nombre du milieu change, car les clients reçoivent un nouveau champ sans incompatibilité. Tous les fichiers de cette mise en production se trouvent dans le commit aa8b83e.
Exercice guidé : deux versions sur une base de données
Section intitulée « Exercice guidé : deux versions sur une base de données »Voici la vérification de fin du module, à réaliser une fois avec les valeurs d’Amira. Utilisez le parcours local, même si vous avez Azure. Les applications infonuagiques de ce cours n’ont pas de base de données. /v1/history y répond donc 503 par conception. La migration s’exécute dans les tests de CI et dans les environnements locaux.
- Créez la branche :
git switch -c feature/score-field(à partir demain). - Ajoutez
migrations/001_create_classifications.sql,migrations/002_add_score.sqletticket_api/migrate.py. Faites les autres changements du commit aa8b83e :Dockerfile, les deux fichiers Compose,main.py,history.py,models.py,routes.py,contract/openapi.json, la version danspyproject.toml,ci.ymlet les tests. - Exécutez
python -m pytest -q. Attendez-vous à 28 tests réussis et 2 ignorés : les tests de base de données sont ignorés sansTEST_DATABASE_URL. - Poussez la branche et ouvrez une demande de tirage :
feature/score-fieldversmain. Attendez-vous à 30 tests dans le journal de CI et à une barrière franchie. Fusionnez la demande. - Trouvez l’empreinte de la nouvelle image. Elle se trouve dans l’artefact
build-infode l’exécution de CI surmain, comme dans Publier les preuves : build-info.json : empreinte, commit et exécution dans un seul fichier. Ensuite, étiquetez le commit de fusionv1.2.0et poussez l’étiquette. Procédez comme pourv1.1.0dans Promouvoir en préproduction : une version sans nouvelle construction. Le module 5 crée le correctif urgent à partir de cette étiquette. - Promouvez l’image en production locale. Le service
migrates’exécute avant l’API. - Démarrez la version 1.1.0 à côté, sur le même réseau et la même base de données. Utilisez votre empreinte de 1.1.0.
- Classez un billet avec chaque version. Regardez ensuite la table.
- Arrêtez l’ancienne version.
Les commandes des étapes 6 à 9, avec les empreintes du dépôt de référence (utilisez les vôtres) :
NEW=ghcr.io/usmanahmed99/ticket-api-ci@sha256:bd2316b56067c738199d6203a23845c97fb7b85b550379411eddd7cc6a2ddab8OLD=ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857ascripts/promote-local.sh production "$NEW"
docker run -d --name ticket-api-old --platform linux/amd64 \ --network ticket-api-production_default -p 127.0.0.1:8083:8000 -e API_KEY=old-key \ -e DATABASE_URL="postgresql://tickets:$(grep '^POSTGRES_PASSWORD=' .env | cut -d= -f2)@db:5432/tickets" \ "$OLD"La sortie de la promotion (simulée, abrégée) :
Container ticket-api-production-migrate-1 Exited Container ticket-api-production-db-1 Healthy Container ticket-api-production-api-1 Healthyok health (200)ok ready (200)ok classify with the key (200)ok classify without a key (401)production now runs ghcr.io/usmanahmed99/ticket-api-ci@sha256:bd2316b5...docker logs ticket-api-production-migrate-1 montre les trois lignes de l’exécuteur, comme dans l’exemple détaillé. Dans votre base de données du module 3, 001 trouve la table créée par 1.1.0 et l’enregistre seulement. Attendez quelques secondes que l’ancienne version démarre (elle fonctionne par émulation sur Apple silicon). Envoyez ensuite le même billet aux deux :
TICKET='{"subject": "Parcel never came", "body": "The courier lost it."}'curl -s -X POST http://127.0.0.1:8082/v1/classify -H "X-API-Key: $(cat secrets/production_api_key.txt)" \ -H "Content-Type: application/json" -d "$TICKET"; echocurl -s -X POST http://127.0.0.1:8083/v1/classify -H "X-API-Key: old-key" \ -H "Content-Type: application/json" -d "$TICKET"; echodocker exec ticket-api-production-db-1 psql -U tickets -d tickets \ -c "SELECT id, request_id, model_version, confidence, score FROM classifications ORDER BY id"La sortie (simulée) :
{"category":"shipping","priority":1,"confidence":0.9,"score":0.9,"model_version":"keywords-1.0"}{"category":"shipping","priority":1,"confidence":0.9,"model_version":"keywords-1.0"} id | request_id | model_version | confidence | score----+--------------+---------------+------------+------- 1 | e3357fb137f9 | keywords-1.0 | 0.7 | 0.7 2 | 169da47b5cdb | keywords-1.0 | 0.9 | 0.9 3 | a533224672fb | keywords-1.0 | 0.9 |(3 rows)Les deux versions classent le billet et enregistrent leur résultat dans la même table. La version 1.2.0 répond avec score; la version 1.1.0 répond sans ce champ, comme avant. La ligne 1 correspond à la requête du test de bon fonctionnement. La ligne 2 vient de 1.2.0. La ligne 3 vient de 1.1.0, donc son score est vide. Dans votre table, les anciennes lignes de 1.1.0 ont aussi un score vide.
Supprimez ensuite l’ancienne version avec docker rm -f ticket-api-old. La production locale continue de fonctionner avec 1.2.0.
Afficher le résultat attendu
pytest -q sur votre ordinateur : 28 passed, 2 skipped (28 réussis, 2 ignorés). Dans la CI : collected 30 items (30 éléments recueillis) et 30 passed (30 réussis), puis Gate passed. (barrière franchie). La promotion affiche les quatre lignes ok (réussite). Les deux réponses de classification diffèrent seulement par score. La table a une ligne par classification. Chaque ligne de 1.2.0 a un score égal à confidence, et chaque ligne de 1.1.0 a un score vide. Si l’ancien conteneur ne répond pas, attendez 10 secondes et envoyez la requête de nouveau. S’il ne répond toujours pas après une minute, lisez docker logs ticket-api-old.
Amira vérifie la classification avec les deux versions et regarde la table. Les deux versions fonctionnent. Les lignes avec un score vide sont celles que 1.1.0 écrit pendant un déploiement. Le schéma indiquait que 1.2.x devait fonctionner avec elles. Le module 5 revient sur cette table.
À vous de jouer : la nouvelle version avant sa migration
Section intitulée « À vous de jouer : la nouvelle version avant sa migration »Changez une condition : démarrez la version 1.2.0 sur une base de données vide, sans exécuter les migrations. Utilisez une base de données temporaire, pas votre production locale. Faites d’abord une prédiction : /ready indique-t-il que l’application est prête? Que répond POST /v1/classify?
Afficher les commandes et la réponse
docker network create try-orderdocker run -d --name try-db --network try-order -e POSTGRES_USER=tickets -e POSTGRES_PASSWORD=pw -e POSTGRES_DB=tickets postgres:18.6-trixiedocker run -d --name try-new --platform linux/amd64 --network try-order -p 127.0.0.1:8085:8000 \ -e API_KEY=k -e DATABASE_URL=postgresql://tickets:pw@try-db:5432/tickets "$NEW"curl -s http://127.0.0.1:8085/ready; echocurl -s -X POST http://127.0.0.1:8085/v1/classify -H "X-API-Key: k" -H "Content-Type: application/json" -d '{"subject": "Refund"}'; echodocker logs try-new 2>&1 | grep UndefinedTableLa sortie (simulée) :
{"status":"ready"}{"error":{"code":"internal_error","message":"Something went wrong on the server.","request_id":"dbd7955e7ed6","fields":[]}}psycopg.errors.UndefinedTable: relation "classifications" does not exist/ready indique que l’application est prête, car il vérifie seulement que la base de données répond. Chaque classification échoue avec 500. Une plateforme enverrait du trafic à cette version. Exécutez maintenant la migration avec la même image, puis réessayez :
docker run --rm --platform linux/amd64 --network try-order \ -e DATABASE_URL=postgresql://tickets:pw@try-db:5432/tickets "$NEW" python -m ticket_api.migrateLes trois lignes de l’exécuteur apparaissent. La requête de classification répond ensuite 200 avec "score":0.7. C’est pourquoi Compose démarre api seulement après la fin de migrate sans erreur. Supprimez les objets : docker rm -f try-new try-db, puis docker network rm try-order.
Renommer en une seule étape
Section intitulée « Renommer en une seule étape »Erreur courante
L'étape de retrait s'exécute pendant que l'ancienne version fonctionne encore
Symptôme (simulé) : une base de données est modifiée en une seule étape. La colonne confidence est renommée score, alors que la version 1.1.0 utilise encore cette base. Chaque requête à la version 1.1.0 échoue alors :
POST /v1/classify 500 {"error":{"code":"internal_error",...}}GET /v1/history 500 {"error":{"code":"internal_error",...}}psycopg.errors.UndefinedColumn: column "confidence" of relation "classifications" does not existpsycopg.errors.UndefinedColumn: column "confidence" does not existLes vérifications de santé et de disponibilité réussissent encore, car elles n’utilisent pas la colonne.
Cause : l’ajout et le retrait ont eu lieu en même temps. La version 1.1.0 insère des valeurs dans confidence et les sélectionne. Après le renommage, aucune version antérieure à 1.2.0 ne peut utiliser cette base de données. Un retour à la version 1.1.0 n’aiderait pas non plus : l’ancien code se retrouve devant la nouvelle table.
Solution :
- Si cela s’est produit, redonnez son ancien nom à la colonne (
ALTER TABLE classifications RENAME COLUMN score TO confidence). La version en cours fonctionnera de nouveau. - Faites le changement par étapes : ajoutez
score(migration002), déployez la version qui écrit dans les deux colonnes, puis remplissez les données manquantes. - Supprimez
confidenceseulement dans une version majeure ultérieure, quand aucune version en cours ni aucun client ne l’utilise. - Testez aussi chaque migration avec la version précédente. La vérification de coexistence de l’exercice guidé le fait.
Pour un vrai service d’IA : les résultats des modèles se trouvent souvent dans des tables comme celle-ci : scores, étiquettes, version du modèle. Un nouveau modèle demande souvent une nouvelle colonne ou un nouveau sens. Chaque déploiement et chaque retour en arrière font coexister des versions pendant un certain temps. La table doit donc servir les deux modèles. Un renommage qui semble propre dans une demande de tirage (pull request) peut arrêter la production pour tous les clients.
Vérifiez votre compréhension
La migration 002 ajoute score sans NOT NULL. Une personne qui révise le code demande NOT NULL avec une valeur par défaut de 0, pour que la colonne ne soit jamais vide. Qu'est-ce qui échoue ou pose problème?
Afficher la réponse
Avec NOT NULL et sans valeur par défaut, la version 1.1.0 ne pourrait insérer aucune ligne : elle n’envoie pas score. Avec une valeur par défaut de 0, les insertions fonctionnent. Mais chaque ligne de la version 1.1.0 indique alors un score de 0, ce qui est faux. Ces billets de soutien avaient une vraie valeur dans confidence. Un score vide signifie « pas encore connu ». Le remplissage des données manquantes (003) le complète ensuite à partir de confidence. Pendant un déploiement, la colonne doit accepter ce que l’ancienne version écrit.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
La version 1.2.0 échoue en production après l'exécution de la migration 002. Amira devrait-elle restaurer la sauvegarde de la base de données faite avant la mise en production?
Afficher la réponse
Non. 002 a seulement ajouté une colonne vide, et la version 1.1.0 l’ignore. Elle déploie l’image de la version 1.1.0 par son empreinte et laisse la colonne. Une restauration remettrait la base de données dans l’état qu’elle avait au moment de la sauvegarde. Elle supprimerait chaque classification effectuée depuis : de vraies données perdues pour annuler un changement qui n’a causé aucun dommage. Gardez des sauvegardes pour les migrations qui modifient ou suppriment des données. Restaurez-les seulement en cas de perte de données.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Prédisez : Amira exécute python -m ticket_api.migrate sur une base de données où 001 est appliquée. La migration 002 contient une erreur dans sa deuxième instruction. La première instruction de 002 est-elle conservée?
Afficher la réponse
Non. Chaque migration s’exécute dans une seule transaction, avec sa ligne dans schema_migrations. Quand la deuxième instruction échoue, toute la migration 002 est annulée. La colonne créée par la première instruction disparaît, et --status (état) indique encore pending 002_add_score (migration 002 en attente). Dans le test de l’auteur, l’exécuteur a affiché applied 001_create_classifications (migration 001 appliquée), puis une SyntaxError (erreur de syntaxe). Il s’est terminé avec le code de sortie 1; 001 est restée appliquée. Après une correction, l’exécution suivante applique 002 depuis le début.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Les anciennes et nouvelles versions partagent la base de données pendant chaque déploiement, déploiement canari et retour en arrière. Chaque migration doit permettre à la version précédente de continuer à fonctionner.
- Ajout et retrait : ajoutez
scoreà côté deconfidencemaintenant (002), écrivez dans les deux colonnes, remplissez les données manquantes plus tard (003), puis supprimezconfidencedans la version 2.0. - Les migrations sont des fichiers numérotés, appliqués une seule fois chacun, dans l’ordre, avec une transaction par fichier. Elles sont enregistrées dans
schema_migrations. L’exécuteur peut fonctionner à chaque déploiement. - Migrez d’abord : l’image contient ses migrations, et Compose démarre
apiseulement après quemigrates’est terminé sans erreur. Le pipeline CI exécute les migrations sur PostgreSQL 18.6. - Une colonne ajoutée ne nécessite aucune restauration pour revenir en arrière. Faites une sauvegarde avant une migration qui modifie ou supprime des données.
- Les versions 1.1.0 et 1.2.0 ont effectué des classifications sur la même base de données. Les lignes de la version 1.1.0 ont un
scorevide.
Leçon suivante : Mise en production progressive