Procédure de correctif urgent
- Leçon 14
- 50 min
- Module 5 : Rétablir et maintenir le processus de mise en production
Leçon 14 sur 15 · CI/CD, tests et mises en production sûresProcédure de correctif urgent
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
Un correctif urgent incite tout le monde à sauter des étapes. Suivez plutôt une courte procédure. Partez de ce qui tourne en production, prouvez le bogue avec un test et exécutez toutes les vérifications. Ramenez ensuite le correctif dans main, pour que la prochaine mise en production ne ramène pas le bogue.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- La séquence du correctif urgent avec Git (branche à partir de la version, correctif, étiquette, fusion en retour). Voir Appliquer un correctif avec cherry-pick : la séquence du correctif urgent et Garder des historiques cohérents : fusionner la version dans main dans L’essentiel de Git et du développement en équipe.
- Les étiquettes, dans Branches de version et étiquettes : étiqueter la version du cours sur Git.
- L’ensemble de règles avec les vérifications obligatoires et « up to date » (à jour, mode strict). Voir Publier les preuves : protéger main avec un ensemble de règles.
- Le flux de travail Release (une étiquette donne sa version à l’image testée, sans nouvelle construction). Voir Promouvoir en préproduction : une version sans nouvelle construction.
- Les trois façons de revenir en arrière, dans Stratégie de retour en arrière : trois éléments peuvent revenir en arrière.
Ce qu’il vous faut sur votre ordinateur
- Votre dépôt
ticket-api-ciavec l’étiquettev1.2.0, de Migrations sûres : exercice guidé : deux versions sur une base de données. Il vous faut aussi un environnement virtuel avecrequirements-lock.txt, de Configurer l’exécuteur : 3. Ajouter les outils et les réglages d’analyse statique. - Parcours simulé : l’environnement de production local (
deploy/local/production.env,.env,secrets/production_api_key.txt). Voir Séparer la configuration : exercice guidé : les fichiers d’environnement local et Promouvoir en préproduction : exercice guidé : promouvoir votre propre empreinte. - Parcours réel : les applications Azure, de Séparer la configuration : exemple détaillé (réel) : deux applications, une image. Il vous faut aussi les environnements avec la personne responsable de la révision obligatoire, de Identifiants et accès : les environnements GitHub.
- Si votre projet ne fonctionne plus, copiez l’instantané
end-of-m04(il contient encore le bogue), comme dans Utiliser un instantané. Donnez-lui l’étiquettev1.2.0. Refaites les réglages GitHub.
Exécuté avec GitHub Actions (exécuteurs ubuntu-24.04) dans le dépôt public Nextia-Intelligence/ticket-api-ci. Docker Desktop 4.81.0 sur macOS (Apple silicon) et Azure CLI 2.88.0 dans canadacentral ont été utilisés. Les étapes Windows et Linux ne sont pas testées.
Le bogue que les vérifications ont manqué
Section intitulée « Le bogue que les vérifications ont manqué »La version 1.2.0 a ajouté score à côté de confidence, avec la migration 002. Dans Migrations sûres : exercice guidé : deux versions sur une base de données, 1.1.0 et 1.2.0 utilisaient une seule base de données. Les deux pouvaient classifier. Amira n’a pas vérifié un autre point de terminaison : l’historique. Voici de nouveau le test, sur l’environnement de production local. La version 1.2.0 y tourne. La version 1.1.0 tourne à côté sous le nom ticket-api-old, sur le même réseau et la même base de données. C’est ce qui arrive pendant un déploiement réel :
KEY=$(cat secrets/production_api_key.txt)scripts/promote-local.sh production ghcr.io/usmanahmed99/ticket-api-ci@sha256:bd2316b56067c738199d6203a23845c97fb7b85b550379411eddd7cc6a2ddab8docker 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" \ ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857acurl -s -X POST http://127.0.0.1:8082/v1/classify -H 'Content-Type: application/json' -H "X-API-Key: $KEY" -d '{"subject":"Package never arrived"}'curl -s -X POST http://127.0.0.1:8083/v1/classify -H 'Content-Type: application/json' -H "X-API-Key: old-key" -d '{"subject":"Package never arrived"}'curl -s -w '\nstatus %{http_code}\n' http://127.0.0.1:8082/v1/history -H "X-API-Key: $KEY"$KEY = Get-Content secrets/production_api_key.txt -Raw$PW = (Select-String '^POSTGRES_PASSWORD=(.*)' .env).Matches[0].Groups[1].Valuebash scripts/promote-local.sh production ghcr.io/usmanahmed99/ticket-api-ci@sha256:bd2316b56067c738199d6203a23845c97fb7b85b550379411eddd7cc6a2ddab8docker 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:$PW@db:5432/tickets" ` ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857acurl.exe -s -X POST http://127.0.0.1:8082/v1/classify -H "Content-Type: application/json" -H "X-API-Key: $KEY" -d '{\"subject\":\"Package never arrived\"}'curl.exe -s -X POST http://127.0.0.1:8083/v1/classify -H "Content-Type: application/json" -H "X-API-Key: old-key" -d '{\"subject\":\"Package never arrived\"}'curl.exe -s -w "`nstatus %{http_code}`n" http://127.0.0.1:8082/v1/history -H "X-API-Key: $KEY"La sortie (simulée; les lignes de déploiement sont abrégées) :
ok 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:bd2316b56067c738199d6203a23845c97fb7b85b550379411eddd7cc6a2ddab8{"category":"other","priority":3,"confidence":0.2,"score":0.2,"model_version":"keywords-1.0"}{"category":"other","priority":3,"confidence":0.2,"model_version":"keywords-1.0"}{"error":{"code":"internal_error","message":"Something went wrong on the server.","request_id":"9dd82ef5ab9b","fields":[]}}status 500Toutes les vérifications de bon fonctionnement ont réussi, et les deux versions classifient. Mais l’historique de 1.2.0 répond 500. Le journal du conteneur api (docker logs ticket-api-production-api-1) explique pourquoi :
pydantic_core._pydantic_core.ValidationError: 1 validation error for HistoryListitems.0.score Input should be a valid number [type=float_type, input_value=None, input_type=NoneType]INFO: 172.21.0.1:57096 - "GET /v1/history HTTP/1.1" 500 Internal Server ErrorEt la table :
id | request_id | model_version | confidence | score----+--------------+---------------+------------+------- 1 | 4d10436731e8 | keywords-1.0 | 0.7 | 0.7 2 | a49f44a4effc | keywords-1.0 | 0.2 | 0.2 3 | ef19e98fb391 | keywords-1.0 | 0.2 |(3 rows)La ligne 3 vient de 1.1.0, qui ne connaît pas score. Le modèle de réponse de 1.2.0 exige un nombre pour score. Une seule ancienne ligne fait donc échouer toute la liste. Dans l’exécution de référence, le même test a donné le même 500 à 18 h 41 UTC.
Pourquoi toutes les vérifications l’ont manqué : les tests de base de données créaient toutes leurs lignes avec le code de 1.2.0. Aucune ligne n’avait donc de score vide. La vérification de bon fonctionnement n’appelait pas /v1/history. Et les applications infonuagiques n’ont pas de base de données. Leur historique répond donc 503 par conception. Le bogue exige deux versions sur une seule base de données. Un déploiement de 1.2.0 crée exactement cette situation.
Correctif urgent ou mise en production normale?
Section intitulée « Correctif urgent ou mise en production normale? »Un correctif urgent est une petite mise en production qui corrige un seul bogue urgent dans la version en production. Rien d’autre. Un correctif normal passe par une branche feature/ vers main et attend la prochaine mise en production. Utilisez un correctif urgent lorsque ces deux conditions sont vraies :
- Le bogue ne peut pas attendre la prochaine mise en production normale.
maincontient des changements après la version publiée que vous ne pouvez pas mettre en production maintenant.
Le correctif urgent part alors de l’étiquette de version, pas de main. v1.2.0 correspond exactement au code en production, donc 1.2.1 = 1.2.0 + un correctif. Dans le dépôt de référence, main avait un changement après v1.2.0 : PR no 6, les lignes de plateforme du fichier Compose local. Ce changement était sans danger, et un correctif passant par main aurait aussi fonctionné. Amira a quand même suivi la procédure, comme l’indique docs/release-process.md. Une procédure utilisée seulement lors d’une vraie urgence est une procédure qui n’a jamais été testée.
Description textuelle du diagramme
La branche de correctif urgent hotfix/1.2.1 part de l’étiquette v1.2.0 (commit c3c7135). Pendant ce temps, main reçoit la PR no 6 (commit 6ae49dc). La branche de correctif urgent reçoit un commit, fc9005a : un test qui échoue, puis le correctif. Elle reçoit l’étiquette v1.2.1. Son image passe manuellement en production, après la préproduction et l’approbation. La branche ne contient pas 6ae49dc. Pour la fusion en retour, la demande de tirage no 7 (hotfix/1.2.1 vers main) était en retard sur main. « Update branch » a donc fusionné main dans la branche de correctif urgent (543b003). Ensuite, la PR no 7 a été fusionnée dans main (3464f2c).
Exemple détaillé : correctif urgent 1.2.1
Section intitulée « Exemple détaillé : correctif urgent 1.2.1 »1. Créer la branche depuis l’étiquette
Section intitulée « 1. Créer la branche depuis l’étiquette »git fetch --tagsgit switch -c hotfix/1.2.1 v1.2.0La sortie :
Switched to a new branch 'hotfix/1.2.1'Vérifiez que vous êtes sur le bon code. git log --oneline -1 montre le commit de l’étiquette, et grep version pyproject.toml montre version = "1.2.0".
2. Un test qui échoue à cause du bogue
Section intitulée « 2. Un test qui échoue à cause du bogue »Écrivez le test avant le correctif. Un test qui échoue d’abord prouve deux choses : il trouve vraiment le bogue et, plus tard, il prouve que le correctif fonctionne. Ajoutez-le à la fin de tests/test_database.py :
def test_history_reads_rows_from_version_1_1(database): """Version 1.1.0 writes no score. 1.2.0 failed with 500 on such rows.""" migrate.main([]) with psycopg.connect(database, autocommit=True) as conn: conn.execute( "INSERT INTO classifications" " (request_id, category, priority, confidence, model_version)" " VALUES ('old111', 'shipping', 1, 0.7, 'keywords-1.0')" ) [row] = History(database).recent(10) assert row["score"] == pytest.approx(0.7)Le INSERT écrit une ligne exactement comme 1.1.0 : sans score. Les tests de base de données exigent une base PostgreSQL dans TEST_DATABASE_URL, comme en CI. Démarrez une base temporaire, puis exécutez les tests de base de données :
docker run -d --name ticket-api-testdb -p 127.0.0.1:5433:5432 \ -e POSTGRES_USER=tickets -e POSTGRES_PASSWORD=ci-only-not-secret -e POSTGRES_DB=tickets postgres:18.6-trixieexport TEST_DATABASE_URL=postgresql://tickets:ci-only-not-secret@127.0.0.1:5433/ticketspython -m pytest -q tests/test_database.pydocker run -d --name ticket-api-testdb -p 127.0.0.1:5433:5432 ` -e POSTGRES_USER=tickets -e POSTGRES_PASSWORD=ci-only-not-secret -e POSTGRES_DB=tickets postgres:18.6-trixie$env:TEST_DATABASE_URL = "postgresql://tickets:ci-only-not-secret@127.0.0.1:5433/tickets"python -m pytest -q tests/test_database.pyLe mot de passe est le même que dans ci.yml. Il ne protège rien, et la base est supprimée après la leçon. Si la première exécution indique « connection refused » (connexion refusée), attendez 5 secondes pour que PostgreSQL démarre. La sortie (abrégée) :
> assert row["score"] == pytest.approx(0.7)E assert None == 0.7 ± 7.0e-07EE comparison failedE Obtained: NoneE Expected: 0.7 ± 7.0e-07
tests/test_database.py:61: AssertionErrorFAILED tests/test_database.py::test_history_reads_rows_from_version_1_1 - ass...1 failed, 2 passed in 0.10sLe test voit le même None que le journal du bogue. Vous avez maintenant une vérification que le pipeline exécutera à chaque changement.
3. Le plus petit correctif
Section intitulée « 3. Le plus petit correctif »Le correctif change une seule requête SQL dans ticket_api/history.py. Pour une ligne sans score, elle renvoie confidence, qui a la même valeur dans les lignes de 1.1.0 :
return conn.execute( "SELECT request_id, category, priority, confidence, score," " model_version, created_at" # Rows from version 1.1.0 have no score: use confidence. "SELECT request_id, category, priority, confidence," " COALESCE(score, confidence) AS score, model_version, created_at" " FROM classifications ORDER BY id DESC LIMIT %s",COALESCE(a, b) donne a, ou b quand a est vide. Le correctif ne change pas la table. Exécutez de nouveau les tests. La sortie :
... [100%]3 passed in 0.10s4. Le reste de la mise en production, et une vérification qui aurait trouvé le bogue
Section intitulée « 4. Le reste de la mise en production, et une vérification qui aurait trouvé le bogue »Un correctif urgent est une mise en production. Il reçoit donc tout ce qu’une mise en production reçoit :
- La version
1.2.1(le dernier nombre : un correctif, aucune nouvelle fonctionnalité), danspyproject.toml,ticket_api/main.pyetcontract/openapi.json(python -m ticket_api.export_contract). - Les notes de version
docs/releases/1.2.1.md. Communiquer une mise en production explique chaque ligne. - Une vérification de bon fonctionnement pour l’historique dans
scripts/smoke.sh. Le bogue est passé parce qu’aucune vérification ne l’appelait :
# 200 with a database, 503 when history is off. A 500 is a bug (as in 1.2.0).check "history" "200|503" "$url/v1/history" -H "X-API-Key: $key"La fonction check compare maintenant avec un motif ([[ "$status" =~ ^($expected)$ ]]). Une vérification peut donc accepter 200 ou 503. Voir toutes les différences dans le commit fc9005a : 7 fichiers, 29 lignes ajoutées, 6 supprimées.
Exécutez ensuite toutes les vérifications, comme le fait la CI. Aucune vérification n’est omise pour un correctif urgent. Un changement urgent est justement celui que les gens testent le moins. Avec TEST_DATABASE_URL toujours défini :
ruff check . && python -m pytest -q && pip-audit -r requirements-run.txt --progress-spinner off && python -m evaluation.run --classifier 1.1La sortie (abrégée) :
All checks passed!31 passed in 0.32sNo known vulnerabilities foundkeywords-1.1 on 33 holdout tickets (baseline keywords-1.0)accuracy 0.909...must-pass failures: 0Gate passed.scripts/check.sh exécute les mêmes vérifications, puis construit l’image et vérifie son bon fonctionnement.
5. Pousser la branche : la CI construit l’image
Section intitulée « 5. Pousser la branche : la CI construit l’image »git add -Agit commit -m "Hotfix 1.2.1: history works with rows from version 1.1.0"git push -u origin hotfix/1.2.1Avant le commit, vérifiez avec git status que .env et secrets/ ne figurent pas dans la liste. Ils sont dans .gitignore. La CI s’exécute lors des poussées vers hotfix/**, pas seulement vers main. La branche de correctif urgent reçoit donc les mêmes vérifications et la même tâche d’image que main : exécution 37669759163. « Lint, test, audit, evaluate » (analyser, tester, auditer, évaluer) a pris 52 secondes. « Build, smoke-test and push the image » (construire, vérifier le bon fonctionnement et pousser l’image) a pris 47 secondes. L’image a reçu l’étiquette sha-fc9005a.
6. Étiqueter la version
Section intitulée « 6. Étiqueter la version »git tag -a v1.2.1 -m "ticket-api 1.2.1: hotfix for GET /v1/history with rows from 1.1.0"git push origin v1.2.1L’étiquette lance le flux de travail Release (exécution 37669994015, 10 secondes). Il donne à l’image sha-fc9005a l’étiquette 1.2.1 et crée la version GitHub à partir de docs/releases/1.2.1.md. Rien n’est reconstruit. Si la CI n’avait pas terminé, le flux de travail Release s’arrêterait avec « CI must build and test this commit first. » (la CI doit d’abord construire et tester ce commit).

La page de version indique le commit (fc9005a) et l’empreinte. Ces deux valeurs correspondent à ce que vous déployez et à ce que vous pouvez retracer.
7. Déployer le correctif urgent manuellement
Section intitulée « 7. Déployer le correctif urgent manuellement »Le flux de travail Deploy démarre automatiquement seulement pour les exécutions CI sur main. Une branche de correctif urgent n’est pas main. Démarrez donc le flux de travail manuellement, avec l’empreinte de la version. Sélectionnez Actions → Deploy → Run workflow (actions → déployer → exécuter le flux de travail), branche main, empreinte sha256:84937455beb63744755622d539748c9adb1772f379c9eb7e4f961c5b7f1bc924. Indiquez la raison « Hotfix 1.2.1: GET /v1/history answered 500 with rows from 1.1.0 » (correctif urgent 1.2.1 : GET /v1/history répondait 500 avec des lignes de 1.1.0). Ou :
gh workflow run deploy.yml -f digest=sha256:84937455beb63744755622d539748c9adb1772f379c9eb7e4f961c5b7f1bc924 \ -f reason="Hotfix 1.2.1: GET /v1/history answered 500 with rows from 1.1.0"Le correctif urgent passe par la préproduction et l’approbation, comme chaque mise en production. Le commentaire de révision était « Hotfix 1.2.1 passed staging. Approved for production. » (le correctif urgent 1.2.1 a réussi en préproduction; approuvé pour la production). Les tâches de l’exécution 37670050850 (réelle) :
Find the image 18:51:44 → 18:51:47 successstaging / Deploy to staging 18:51:52 → 18:52:43 successproduction / Deploy to production 18:52:59 → 18:53:50 successEnviron 2 minutes du démarrage à la production. Consultez les détails de l’exécution. Elle a utilisé les fichiers de flux de travail de main au commit 6ae49dc, pas ceux de la branche de correctif urgent. Les étapes de déploiement viennent toujours de main, même pour un correctif urgent. C’est voulu : le processus de déploiement a une seule version. Communiquer une mise en production en montre une conséquence.
Parcours simulé. Déployez la même empreinte localement. Exécutez la commande depuis une copie de travail de main (l’erreur fréquente ci-dessous explique pourquoi) :
scripts/promote-local.sh production ghcr.io/usmanahmed99/ticket-api-ci@sha256:84937455beb63744755622d539748c9adb1772f379c9eb7e4f961c5b7f1bc924curl -s -w '\nstatus %{http_code}\n' 'http://127.0.0.1:8082/v1/history?limit=3' -H "X-API-Key: $KEY"La sortie (simulée, abrégée) :
ok health (200)ok ready (200)ok classify with the key (200)ok classify without a key (401)ok history (200)production now runs ghcr.io/usmanahmed99/ticket-api-ci@sha256:84937455beb63744755622d539748c9adb1772f379c9eb7e4f961c5b7f1bc924{"items":[{"request_id":"119fbf2734a9",…},{"request_id":"ef19e98fb391","category":"other","priority":3,"confidence":0.2,"score":0.2,"model_version":"keywords-1.0",…},…]}status 200L’historique fonctionne, et l’ancienne ligne ef19e98fb391 affiche un score de 0,2, tiré de son confidence. La vérification de bon fonctionnement de history réussit. Dans la base de données, la valeur de la ligne est toujours vide. Le correctif change la façon dont l’API lit les données, pas les données elles-mêmes. Stratégie de retour en arrière répare les données avec 003.
8. Fusionner le correctif dans main
Section intitulée « 8. Fusionner le correctif dans main »La production contient le correctif. main ne le contient pas. Si la prochaine version vient de main, le bogue revient. Ouvrez donc immédiatement une demande de tirage hotfix/1.2.1 vers main, avec la raison dans la description. Dans le dépôt de référence, c’était la PR no 7, ouverte à 18 h 55.
La PR no 7 ne pouvait pas être fusionnée au début. Son état était BEHIND (en retard) : main contenait la PR no 6. L’ensemble de règles exige qu’une branche soit à jour avec main avant la fusion (mode strict). Sur la page de la demande de tirage, GitHub indique que la branche est en retard sur la branche de base. Il propose Update branch aux personnes qui peuvent fusionner. La personne responsable de la révision sélectionne ce bouton. Cela fusionne main dans la branche de correctif urgent (commit 543b003, « Merge branch ‘main’ into hotfix/1.2.1 », fusionner la branche main dans hotfix/1.2.1). Toutes les vérifications s’exécutent de nouveau sur le résultat. Le mode strict existe pour cette raison. Les vérifications doivent réussir sur le code que main contiendra après la fusion, pas seulement sur la branche. Avec l’interface en ligne de commande, c’est pareil : gh pr update-branch 7.

Les vérifications ont de nouveau réussi, et la PR no 7 a été fusionnée à 18 h 58 sous 3464f2c. Cette poussée vers main a démarré automatiquement la CI, puis le flux de travail Deploy. Le commentaire d’approbation était « main now has hotfix 1.2.1. Staging passed, including the new history check. » (main contient maintenant le correctif urgent 1.2.1; la préproduction a réussi, y compris la nouvelle vérification de l’historique).
9. Vérifier qu’aucun correctif n’est perdu
Section intitulée « 9. Vérifier qu’aucun correctif n’est perdu »Ne vous fiez pas à « merged » (fusionné). Vérifiez trois choses dans votre propre clone, après git switch main et git pull :
git branch --contains v1.2.1git log main --oneline | grep Hotfixgrep -n "def test_history_reads_rows_from_version_1_1" tests/test_database.pyLa sortie (du dépôt d’exercice local, abrégée) :
hotfix/1.2.1* mainb3ceff1 Hotfix 1.2.1: history works with rows from version 1.1.051:def test_history_reads_rows_from_version_1_1(database):main contient le commit de l’étiquette. Le commit du correctif urgent est dans l’historique de main. Le test est dans les fichiers de main, donc chaque changement ultérieur l’exécute. Le bogue ne peut pas revenir sans une vérification au rouge. Utilisez git branch -r --contains v1.2.1 pour voir aussi les branches sur GitHub.
Erreur courante
Les outils de la branche de correctif urgent sont anciens
Symptôme (simulé, exécution de référence) : après le correctif urgent, Amira a déployé 1.2.1 localement depuis sa copie de travail de hotfix/1.2.1. Elle utilisait son Mac (Apple silicon). Elle a ensuite demandé l’historique :
$ scripts/promote-local.sh production ghcr.io/usmanahmed99/ticket-api-ci@sha256:84937455… # 1.2.1$ curl http://127.0.0.1:8082/v1/history{"error":{"code":"internal_error","message":"Something went wrong on the server.","request_id":"bd725fc294ad","fields":[]}}status 500Toujours 500, après le correctif. La promotion avait échoué, et 1.2.0 tournait encore.
Cause : la branche de correctif urgent avait été créée depuis v1.2.0. Son deploy/local/compose.yaml était celui de v1.2.0, sans la ligne platform: linux/amd64. Cette ligne est arrivée plus tard dans la PR no 6 sur main. L’image existe seulement pour linux/amd64. Sur Apple silicon, Docker ne pouvait donc pas la récupérer. Il indiquait « no matching manifest for linux/arm64/v8 » (aucun manifeste correspondant pour linux/arm64/v8), comme dans Promouvoir en préproduction : l’image qui ne démarrait pas sur un Mac. Une branche de correctif urgent contient le code de la version, mais aussi ses anciens outils. Tous les correctifs apportés plus tard aux scripts, aux fichiers Compose ou à la documentation sur main sont absents. (Dans votre propre dépôt, v1.2.0 contient déjà les lignes platform. Vous les avez ajoutées dans Promouvoir en préproduction : l’image qui ne démarrait pas sur un Mac. Cette erreur ne vous arrive donc pas. Le piège reste le même pour chaque outil ajouté à main après l’étiquette.)
Correctif :
- Exécutez les outils de déploiement depuis
main:git switch main, puis la même commandepromote-local.shavec la même empreinte. Seule l’image vient du correctif urgent. Dans l’exécution de référence, l’historique a ensuite répondu200. - Le flux de travail Deploy le fait déjà : il utilise toujours les fichiers de flux de travail de
main. - Fusionnez rapidement le correctif urgent dans
main, pour que les deux branches ne s’éloignent pas davantage.
Si l’image est déjà sur votre ordinateur, Docker ne la récupère pas. L’ancien fichier Compose peut alors fonctionner par hasard. Ne comptez pas là-dessus : exécutez les outils depuis main chaque fois.
Pour un vrai service d’IA : c’est aussi vrai pour la configuration de service des modèles, les données d’évaluation et les scripts de déploiement. Un correctif créé depuis une ancienne version ne doit pas ramener d’anciens outils. Gardez le processus de déploiement sur main et changez seulement l’artefact.
Exercice guidé : un correctif urgent dans un dépôt d’exercice
Section intitulée « Exercice guidé : un correctif urgent dans un dépôt d’exercice »Faites l’exercice dans une copie jetable. Ainsi, une erreur ne coûte rien. Vous avez besoin de Git et de l’instantané end-of-m04.
- Copiez l’instantané
end-of-m04dans un nouveau dossier, par exemplehotfix-practice. Dans ce dossier, exécutezgit init -b main,git add -A,git commit -m "Version 1.2.0"etgit tag v1.2.0. - Faites avancer
main: ajoutez une ligne àREADME.md, puis créez un commit surmain. - Créez la branche du correctif urgent à partir de l’étiquette :
git switch -c hotfix/1.2.1 v1.2.0. Vérifiez queREADME.mdne contient pas votre nouvelle ligne. - Ajoutez le test
test_history_reads_rows_from_version_1_1. Démarrez la base de données de test, puis exécutezpython -m pytest -q tests/test_database.py. Le test doit échouer avecassert None == 0.7. - Appliquez le correctif dans
ticket_api/history.py. Relancez les tests :3 passed(3 tests réussis). - Changez la version pour
1.2.1aux trois endroits, ajoutez la vérification sommaire de l’historique et rédigezdocs/releases/1.2.1.md. - Exécutez toutes les vérifications. Créez un commit avec le message « Hotfix 1.2.1: history works with rows from version 1.1.0 ». Ajoutez l’étiquette
v1.2.1. - Vérifiez le piège :
git branch --contains v1.2.1ne doit pas encore affichermain. - Mettez la branche à jour : exécutez
git merge maindepuishotfix/1.2.1. Puis exécutezgit switch mainetgit merge --no-ff hotfix/1.2.1. - Exécutez les trois vérifications de l’étape 9 de l’exemple détaillé.
Afficher le résultat attendu
Après l’étape 7, git log --oneline --graph --all --decorate montre deux branches issues de v1.2.0 :
* b3ceff1 (HEAD -> hotfix/1.2.1, tag: v1.2.1) Hotfix 1.2.1: history works with rows from version 1.1.0| * 8a1d23c (main) Describe the local environments in the README|/* c63905b (tag: v1.2.0) Version 1.2.0L’étape 8 affiche seulement * hotfix/1.2.1. git rev-list --count hotfix/1.2.1..main affiche 1 : la branche a un commit de retard sur main. C’est l’état BEHIND (en retard) de la demande de tirage nº 7. Après l’étape 9 :
* b0c1a03 (HEAD -> main) Merge hotfix 1.2.1 back into main|\| * aaf466e (hotfix/1.2.1) Merge branch 'main' into hotfix/1.2.1| |\| |/|/|* | 8a1d23c Describe the local environments in the README| * b3ceff1 (tag: v1.2.1) Hotfix 1.2.1: history works with rows from version 1.1.0|/* c63905b (tag: v1.2.0) Version 1.2.0La forme est la même que dans le diagramme. L’étape 10 affiche main, trouve le commit du correctif urgent et trouve le test. Vos identifiants de commit sont différents. La vérification complète donne 31 passed (31 tests réussis) et « Gate passed. » (barrière franchie).
Supprimez la base de données de test quand vous avez terminé : docker rm -f -v ticket-api-testdb.
À vous de jouer : le correctif a d’abord été fait sur main
Section intitulée « À vous de jouer : le correctif a d’abord été fait sur main »Parfois, l’ordre est inversé. Un développeur corrige d’abord le bogue dans une demande de tirage (pull request) vers main. Ensuite, l’équipe décide que la production en a besoin immédiatement. main contient aussi d’autres changements qui ne sont pas prêts. Dans votre dépôt d’exercice, créez le correctif dans un commit sur main. Comment créer la version 1.2.1 à partir de ce commit, sans les autres changements de main? Quelles vérifications prouvent que la version 1.2.1 contient le correctif, et rien d’autre?
Afficher la réponse
Créez la branche du correctif urgent à partir de l’étiquette, comme avant. Copiez seulement le commit du correctif avec cherry-pick (Appliquer un correctif avec cherry-pick dans le cours sur Git) :
git switch -c hotfix/1.2.1 v1.2.0git cherry-pick <commit of the fix on main>Suivez ensuite les mêmes étapes : version, notes, toutes les vérifications, étiquette v1.2.1, puis déploiement de l’empreinte. Les preuves : le nouveau test échoue sur v1.2.0 et réussit sur v1.2.1; git diff v1.2.0 v1.2.1 --stat affiche seulement les fichiers du correctif et de la mise en production; git log v1.2.0..v1.2.1 --oneline montre un seul commit. Dans cet ordre, main contient déjà le correctif. Fusionnez quand même la branche du correctif urgent dans la branche principale. Vous pouvez aussi vérifier avec git log main --oneline | grep que le correctif s’y trouve. Ainsi, le changement de version et les notes de mise en production se trouvent aussi sur main.
Vérifiez votre compréhension
Le correctif urgent presse. Sam propose de sauter la barrière d'évaluation de l'IA et l'audit cette fois. Le changement touche une seule ligne SQL. Que répondez-vous?
Afficher la réponse
On ne saute aucune vérification pour un correctif urgent. Les gens vérifient moins les changements urgents, et la production est déjà en difficulté. Un deuxième bogue serait maintenant pire que le premier. Les vérifications sont rapides. Dans l’exécution de référence, elles ont toutes pris 52 secondes, et la tâche de construction de l’image a pris 47 secondes. Elles ont prouvé quelque chose d’utile : le nouveau test échouait sans le correctif et réussissait avec lui. La barrière a aussi montré que le modèle n’avait pas changé. Un changement SQL d’une seule ligne peut quand même briser d’autres requêtes ou le contrat. La procédure reste la même; seule la branche change.
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 déploie la version 1.2.1 depuis la branche du correctif urgent et oublie la demande de tirage vers main. Deux semaines plus tard, la version 1.3.0 est mise en production depuis main. Que se passe-t-il?
Afficher la réponse
La version 1.3.0 est construite depuis main, qui n’a jamais reçu le correctif. La requête d’historique sur main lit encore score sans COALESCE. Le bogue revient donc en production : GET /v1/history répond 500 pour toute ligne sans score. Le nouveau test de base de données et la vérification sommaire de l’historique manquent aussi. Aucune vérification ne détecte donc le bogue. C’est une régression. git branch --contains v1.2.1 le montrerait : main ne figure pas dans la liste. Voilà pourquoi la procédure de correctif urgent se termine par une fusion dans la branche principale. C’est aussi pourquoi la vérification après cette fusion fait partie de la procédure.
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 demande de tirage nº 7 avait des vérifications réussies, mais son état était BEHIND. Pourquoi l'ensemble de règles bloque-t-il la fusion, et que fait Update branch?
Afficher la réponse
L’ensemble de règles est strict : une branche doit être à jour avec main. Les vérifications de la demande de tirage nº 7 ont porté uniquement sur la branche du correctif urgent. Celle-ci ne contenait pas la demande de tirage nº 6. Après une fusion, main contiendrait les deux, et personne n’avait vérifié cette combinaison. Update branch (mettre la branche à jour) fusionne main dans la branche du correctif urgent (commit 543b003). Chaque vérification obligatoire s’exécute alors de nouveau sur le code combiné. La demande de tirage peut être fusionnée seulement après ces vérifications. Sans le mode strict, deux changements qui réussissent séparément peuvent briser main ensemble.
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
- Un correctif urgent est une petite mise en production qui corrige un seul problème dans la version en production. Partez de l’étiquette de mise en production :
git switch -c hotfix/1.2.1 v1.2.0. - Écrivez un test qui échoue à cause du bogue, puis faites le plus petit correctif possible. Ajoutez la vérification qui aurait détecté le bogue (ici, la vérification sommaire de l’historique).
- Exécutez toutes les vérifications. La CI s’exécute sur
hotfix/**et construit l’image. L’étiquettev1.2.1met cette image en production sans nouvelle construction. - Déployez l’empreinte manuellement avec le flux de travail Deploy (déployer) : préproduction, approbation, production. Les étapes de déploiement proviennent de
main. - Fusionnez immédiatement le correctif urgent dans
main. Si la demande de tirage est BEHIND, utilisez Update branch et laissez les vérifications s’exécuter de nouveau. - Vérifiez :
git branch --contains v1.2.1affichemain, et le test se trouve surmain. Exécutez les outils locaux depuismain: la branche du correctif urgent contient d’anciens outils.
Leçon suivante : Communiquer une mise en production