From 2fa3e35a88394ff398838aa96b69fc9d0af5238a Mon Sep 17 00:00:00 2001 From: Nikolaz Date: Tue, 13 Oct 2026 20:51:26 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20arr=C3=AAt=20propre=20de=20run-dev.sh=20?= =?UTF-8?q?sans=20d=C3=A9grader=20le=20terminal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remplace le job control (set -m) par un kill récursif de l'arbre de process de chaque service (tuer_arbre via pgrep -P), évitant que les réglages du terminal interactif (flèches, historique) ne soient altérés après Ctrl+C. Ajout d'un stty sane de sécurité en fin de cleanup. --- run-dev.sh | 77 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/run-dev.sh b/run-dev.sh index fdd6b1a..d896a07 100755 --- a/run-dev.sh +++ b/run-dev.sh @@ -4,7 +4,8 @@ # À utiliser hors Docker, pour le développement local. # # Usage : ./run-dev.sh -# Arrêt : Ctrl+C (backend ET frontend sont arrêtés ensemble, port backend libéré). +# Arrêt : Ctrl+C — backend et frontend (et leurs process enfants : Kestrel, +# ng serve, esbuild) sont arrêtés ensemble, les ports 4200/8080 libérés. # # Le port du backend est paramétrable via BACKEND_PORT (ex. BACKEND_PORT=5080 ./run-dev.sh). # Ce même port est transmis au backend (dotnet --urls) ET au proxy de dev du front @@ -12,16 +13,22 @@ set -uo pipefail -# --- Groupe de process dédié ------------------------------------------------ +# --- Arrêt propre des sous-process : rappel d'implémentation ----------------- # Problème résolu : à l'arrêt, « dotnet run » / « npm start » lancent des process # ENFANTS (le vrai serveur Kestrel, esbuild…) qui survivaient à un simple kill du -# PID parent, laissant le port backend occupé. Solution : exécuter tout le script -# dans sa PROPRE session/groupe de process (via setsid), puis tuer le GROUPE ENTIER -# au cleanup. On se relance une seule fois sous setsid si ce n'est pas déjà le cas. -if [[ -z "${RUN_DEV_SETSID:-}" ]] && command -v setsid >/dev/null 2>&1; then - export RUN_DEV_SETSID=1 - exec setsid "$0" "$@" -fi +# PID parent, laissant les ports occupés. +# +# Choix d'implémentation : backend et frontend sont lancés en arrière-plan (« & ») comme +# ENFANTS DIRECTS du script. Au cleanup, on tue RÉCURSIVEMENT tout l'arbre de process de +# chacun (via les enfants rapportés par « ps --ppid »), ce qui termine Kestrel / ng serve +# / esbuild et leurs descendants. Le script reste attaché au terminal → Ctrl+C fonctionne +# et le trap, retiré dès l'entrée de cleanup, ne boucle pas. +# +# On N'UTILISE NI « set -m » (job control) NI « setsid » : +# - set -m laisse le terminal dégradé après Ctrl+C (plus de flèches/historique ni Tab), +# car les enfants interactifs (node/ng serve) modifient les réglages du terminal ; +# - setsid fork et fausse « $! » (surveillance kill -0 / wait non fiables). +# Par sécurité, le cleanup restaure quand même le terminal via « stty sane ». RACINE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -82,6 +89,9 @@ export Auth__FrontendBaseUrl="${Auth__FrontendBaseUrl:-http://localhost:4200}" # dans les logs pour tester la réinitialisation sans email réel. echo "→ Démarrage du backend sur http://localhost:$BACKEND_PORT (base : $RACINE/backend/SchotzIadKmTracker.Api/trajets.db)" +# Lancement classique en arrière-plan : le backend est un ENFANT DIRECT du script, +# donc $!, kill -0 et wait restent fiables (contrairement à setsid, qui fork et +# fausse $!). Au cleanup, on tue récursivement tout l'arbre de PID_BACK (Kestrel inclus). dotnet run --project "$RACINE/backend/SchotzIadKmTracker.Api" --urls "http://localhost:$BACKEND_PORT" & PID_BACK=$! @@ -99,23 +109,46 @@ echo "→ Nettoyage du cache Angular (.angular/cache)" rm -rf "$RACINE/frontend/.angular/cache" echo "→ Démarrage du frontend sur http://localhost:4200 (proxy /api → :$BACKEND_PORT ; première compilation : patiente…)" +# Même principe que le backend : enfant direct du script. L'arbre (npm → ng serve → +# esbuild) sera tué récursivement au cleanup à partir de PID_FRONT. ( cd "$RACINE/frontend" && npm start ) & PID_FRONT=$! -# --- Arrêt propre : on tue TOUT le groupe de process ------------------------ -# Comme le script tourne dans sa propre session (setsid), son PID est aussi le PGID. -# `kill -- -$$` envoie le signal à TOUT le groupe (backend, frontend et leurs enfants), -# ce qui libère réellement le port backend. Repli ciblé par sécurité. -cleanup() { - echo "" - echo "→ Arrêt (groupe de process)…" - # Signal au groupe entier (le '-' devant le PID = groupe). $$ = PID du script = PGID. - kill -TERM -- "-$$" 2>/dev/null || true - # Repli : au cas où certains process ne seraient pas dans le groupe. - kill "$PID_BACK" "$PID_FRONT" 2>/dev/null || true - pkill -f "SchotzIadKmTracker.Api" 2>/dev/null || true +# Tue récursivement un process et toute sa descendance (enfants, petits-enfants…). +# On remonte les enfants AVANT de tuer le parent pour ne pas perdre la filiation, puis +# on envoie TERM à chaque PID. Robuste et sans effet sur le terminal (ni set -m ni setsid). +tuer_arbre() { + local pid="$1" + [ -z "$pid" ] && return 0 + local enfant + for enfant in $(pgrep -P "$pid" 2>/dev/null); do + tuer_arbre "$enfant" + done + kill -TERM "$pid" 2>/dev/null || true } -trap cleanup EXIT INT TERM + +# --- Arrêt propre : on tue l'ARBRE de chaque service (pas le script lui-même) -- +# On tue le groupe de process (PGID) du backend et du frontend créés par setsid, ce +# qui termine Kestrel / ng serve / esbuild et leurs enfants. On NE touche PAS au groupe +# du script : Ctrl+C reste fonctionnel et le trap, retiré dès l'entrée de cleanup, ne +# boucle pas. On restaure enfin le terminal (stty sane) au cas où un enfant interactif +# l'aurait laissé dans un état dégradé (flèches/historique, autocomplétion Tab). +cleanup() { + trap - INT TERM EXIT + echo "" + echo "→ Arrêt…" + # Tue tout l'arbre du frontend puis du backend (service + enfants : ng serve, esbuild, + # Kestrel…). On capture les PID avant qu'ils ne disparaissent. + tuer_arbre "${PID_FRONT:-}" + tuer_arbre "${PID_BACK:-}" + # Dernier filet : process résiduels identifiables du projet, au cas où. + pkill -f "SchotzIadKmTracker.Api" 2>/dev/null || true + pkill -f "ng serve" 2>/dev/null || true + # Restaure un terminal sain (écho, flèches/historique, autocomplétion) au cas où un + # enfant interactif (node/ng serve) aurait modifié les réglages du terminal. + stty sane 2>/dev/null || true +} +trap cleanup INT TERM EXIT # --- Attente active : ng serve prêt à répondre en HTTP 200 ------------------ # La première compilation (surtout après vidage du cache) peut prendre 30–60 s.