Transmettre le signal d’arrêt

DockerBeginner
Pratiquer maintenant

Introduction

Paper & Pine transforme des programmes d’événements en file d’attente en véritables PDF. Avant de suspendre la production, il doit terminer le document courant de trois pages, laisser la tâche suivante en attente et préserver le PDF du matin terminé. Le worker Python fourni sait déjà finir sa tâche courante après une demande d’arrêt, mais son shell d’entrée empêche actuellement cette demande de lui parvenir.

Vous devez connaître les chemins dans le terminal, les bases de Docker et les journaux de conteneurs. Le petit fichier Compose et le comportement du shell utilisés ici sont expliqués avant emploi. La programmation Python et une imprimante physique sont inutiles : le produit est un PDF téléchargeable et décodable.

Utilisez Workstation et Print Desk. Les files indépendantes d’essai et de livraison permettent d’examiner un échec contrôlé sans perdre la progression de livraison. Le mode pédagogique s’arrête après la première page rendue jusqu’à réception d’une demande d’arrêt, puis ajoute une pause annoncée de 0,5 seconde entre les pages restantes. Ces pauses rendent la décision visible ; elles ne constituent pas un banc d’essai de vitesse de production. Prévoyez environ 45 minutes, lecture et erreurs ordinaires comprises ; il s’agit d’une estimation de l’auteur.

Transmettre la demande d’arrêt au worker

Dans cette étape, vous allez observer un arrêt d’essai échoué, réparer le shell d’entrée et réaliser une véritable livraison dans le même worker que celui qui reçoit la demande d’arrêt.

Commencer par un véritable programme terminé

Commencez dans Print Desk. Sous Delivery attempt, ouvrez Preview text pour Morning welcome handout et sélectionnez Download PDF. L’aperçu est décodé à partir de ce PDF enregistré de deux pages, pas reconstruit depuis le texte source. Revenez avec Back to Print Desk. Le document courant Community open day handout est en attente ; Volunteer notes doit rester en attente après ce transfert.

Le bureau sépare l’essai de la livraison et ne propose au départ que les documents antérieurs :

Print Desk avant la production du document courant

La colonne Practice attempt est une copie distincte de la file pédagogique, pas une seconde machine. Chaque colonne a sa propre sortie et son propre état de worker. Un PDF courant ne devient téléchargeable qu’après finalisation de tout le document. Rendre la page 1 en interne ne produit pas encore un fichier PDF complet.

Observer pourquoi un arrêt d’essai échoue

Passez à Workstation, qui démarre dans /home/labex/project/print-signal. cd permet d’y revenir et cat lit un fichier :

cd /home/labex/project/print-signal
cat compose.trial.yaml

Compose regroupe les paramètres sous services.worker. Son image préparée contient le worker et les bibliothèques PDF. user correspond déjà aux identifiants numériques réels de votre compte, pour que les sorties restent modifiables ; ne remplacez pas ces valeurs. /input, en lecture seule, contient les tâches d’origine, /work est l’état et la sortie modifiables de cet essai, et /entry.sh est son script d’entrée en lecture seule. :ro signifie lecture seule. entrypoint: ["/bin/sh", "/entry.sh"] démarre directement ce shell comme processus 1 du conteneur, appelé PID 1. Un conteneur partage le noyau de la VM, mais possède sa propre vue des processus.

stop_grace_period: 10s accorde à l’application une fenêtre d’arrêt finie de dix secondes. Docker envoie d’abord SIGTERM, la demande normale de terminaison. Une fois le délai écoulé, il peut envoyer SIGKILL, qui termine de force les processus et ne peut pas être traité pour finir le travail. Envoyer un signal à PID 1 ne le transmet pas automatiquement à tous ses enfants.

L’entrée d’essai existante démarre Python comme enfant en arrière-plan avec &, puis wait l’attend. Le shell reste PID 1. Lisez ce script fourni :

cat trial-entry.sh

Le shell n’a pas de gestionnaire de transmission. Le PID 1 d’un conteneur possède un comportement par défaut particulier vis-à-vis des signaux ; ce shell peut donc rester actif tandis que Python ne reçoit jamais la demande TERM.

Démarrez uniquement le projet d’essai. -f sélectionne son fichier, -p regroupe ses ressources, up -d le démarre en arrière-plan, et les dernières options utilisent les images préparées sans téléchargement ni construction :

docker compose -f compose.trial.yaml -p print-trial up -d --pull never --no-build

Passez à Print Desk, rechargez et attendez que Practice attempt affiche Training pause after page 1; waiting for stop request. Le worker a réellement rendu la page 1 et attend volontairement. Il n’y a pas de fenêtre temporelle étroite à viser.

Passez à Workstation. docker exec exécute une commande dans un conteneur existant. Linux expose les informations de processus sous /proc ; /proc/1/comm dans ce conteneur nomme la commande de son PID 1. Cette observation de lecture seule doit afficher sh :

docker exec print-trial cat /proc/1/comm

stop demande à ce service de s’arrêter avec son délai configuré :

docker compose -f compose.trial.yaml -p print-trial stop worker

La commande d’arrêt elle-même peut se terminer avec 0 même si le worker a été tué de force : cela signifie que Docker a traité l’opération d’arrêt, pas que le programme a été achevé. docker inspect lit le conteneur conservé. Le modèle entre apostrophes sélectionne le code de sortie de son worker :

docker inspect print-trial --format '{{.State.ExitCode}}'
docker logs print-trial

Vous devez obtenir le code de sortie 137 sans événement worker stop-received ni completed. Dans cet essai contrôlé, le délai a expiré et Docker a forcé l’arrêt ; 137 seul n’est pas un diagnostic général de tous les échecs de conteneur. Le journal contient un événement JSON par ligne : event nomme l’observation, job identifie le programme et page enregistre la progression réelle du rendu.

Passez à Print Desk et rechargez. L’essai n’a pas de PDF courant finalisé, tandis que son document antérieur et la file de livraison intacte restent disponibles.

Remplacer le shell par le worker

Passez à Workstation. Modifiez uniquement entry.sh de livraison, en laissant intacts trial-entry.sh, le programme d’entrée, les PDF existants et les autres paramètres. Le exec du shell remplace le processus shell courant par le programme nommé. Python devient donc PID 1 et son gestionnaire TERM fourni reçoit la demande de Docker.

Ce here-document littéral écrit le petit script complet. > remplace entry.sh ; le marqueur SH entre apostrophes empêche les substitutions du shell jusqu’à la ligne de fermeture. Le fichier n’a pas besoin du bit exécutable, car le /bin/sh configuré le lit :

cat > entry.sh <<'SH'
#!/bin/sh
exec python3 -B /app/worker.py
SH
cat entry.sh

Démarrez le projet de livraison indépendant, dont le délai de dix secondes suffit déjà pour ce document de trois pages :

docker compose -p print-delivery up -d --pull never --no-build

Passez à Print Desk, rechargez et attendez le message de pause pédagogique de Delivery attempt. Revenez à Workstation et lisez de nouveau PID 1 :

docker exec print-delivery cat /proc/1/comm

Vous devez voir python3, plutôt que le shell en attente. Demandez un arrêt normal :

docker compose -p print-delivery stop worker
docker inspect print-delivery --format '{{.State.ExitCode}}'
docker logs print-delivery

Le code de sortie attendu est 0. Le même worker journalise stop-received, les événements page-completed restants, completed pour le programme courant et worker-stopped. Un nouveau processus qui compléterait plus tard le PDF manquant ne prouverait pas que ce worker a achevé sa tâche.

Examiner le fichier livré et la file préservée

Passez à Print Desk, rechargez et ouvrez Preview text du document courant sous Delivery attempt. Les trois pages décodées, leurs titres de section, l’identifiant du programme et les numéros de page doivent être présents. Téléchargez le véritable PDF et ouvrez-le. Revenez au bureau : Morning welcome handout doit toujours avoir ses deux pages d’origine, et Volunteer notes doit rester en attente sans PDF généré. Conservez le conteneur print-delivery arrêté normalement pour ses preuves d’inspection natives.

Si un nom est mal orthographié, lisez l’erreur et utilisez le nom de conteneur indiqué ; par exemple, docker logs print-workr ne peut pas trouver cette livraison, tandis que la commande affichée docker logs print-delivery la lit. Ne créez pas un PDF de remplacement à la main. Les vérifications lisent les faits réels de l’arrêt et décodent chaque page, puis réexécutent votre entrée enregistrée dans un dispositif de programme isolé sans changer la progression réelle.

Récupérer après une livraison infructueuse

Si votre tentative de livraison échoue, gardez le conteneur arrêté assez longtemps pour lire ses journaux et son code de sortie. Corrigez uniquement la configuration d’entrée ou du délai. L’action de récupération fournie refuse un conteneur actif ou terminé avec succès ; pour un worker du cours arrêté en échec, elle remet uniquement la tâche courante en file et conserve les artefacts échoués dans delivery/attempt-history/. Elle préserve le PDF antérieur, les entrées d’origine et la tâche suivante en attente :

python3 /opt/labex/dk05/source/retry.py

Après cette récupération explicite, supprimez uniquement les conteneurs du projet de livraison échoué avec docker compose -p print-delivery down, puis répétez la séquence affichée : démarrage de livraison, attente de la pause et arrêt. Aucun PDF source n’est régénéré, et cette récupération n’est jamais exécutée par un onglet ou une vérification de score. Ne réinitialisez pas la VM et ne changez pas le JSON de la file pour masquer un essai échoué.

Résumé

Vous avez vu comment un shell PID 1 en attente peut cacher une demande d’arrêt à son enfant, puis utilisé exec pour permettre au worker fourni de recevoir TERM directement. Le worker de livraison d’origine a terminé son PDF de trois pages, s’est terminé normalement, a préservé le document du matin et laissé la tâche suivante en attente.