fix: arrêt propre de run-dev.sh sans dégrader le terminal
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.
This commit is contained in:
+55
-22
@@ -4,7 +4,8 @@
|
|||||||
# À utiliser hors Docker, pour le développement local.
|
# À utiliser hors Docker, pour le développement local.
|
||||||
#
|
#
|
||||||
# Usage : ./run-dev.sh
|
# 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).
|
# 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
|
# Ce même port est transmis au backend (dotnet --urls) ET au proxy de dev du front
|
||||||
@@ -12,16 +13,22 @@
|
|||||||
|
|
||||||
set -uo pipefail
|
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
|
# 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
|
# 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
|
# PID parent, laissant les ports occupés.
|
||||||
# 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.
|
# Choix d'implémentation : backend et frontend sont lancés en arrière-plan (« & ») comme
|
||||||
if [[ -z "${RUN_DEV_SETSID:-}" ]] && command -v setsid >/dev/null 2>&1; then
|
# ENFANTS DIRECTS du script. Au cleanup, on tue RÉCURSIVEMENT tout l'arbre de process de
|
||||||
export RUN_DEV_SETSID=1
|
# chacun (via les enfants rapportés par « ps --ppid »), ce qui termine Kestrel / ng serve
|
||||||
exec setsid "$0" "$@"
|
# / esbuild et leurs descendants. Le script reste attaché au terminal → Ctrl+C fonctionne
|
||||||
fi
|
# 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)"
|
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.
|
# 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)"
|
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" &
|
dotnet run --project "$RACINE/backend/SchotzIadKmTracker.Api" --urls "http://localhost:$BACKEND_PORT" &
|
||||||
PID_BACK=$!
|
PID_BACK=$!
|
||||||
|
|
||||||
@@ -99,23 +109,46 @@ echo "→ Nettoyage du cache Angular (.angular/cache)"
|
|||||||
rm -rf "$RACINE/frontend/.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…)"
|
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 ) &
|
( cd "$RACINE/frontend" && npm start ) &
|
||||||
PID_FRONT=$!
|
PID_FRONT=$!
|
||||||
|
|
||||||
# --- Arrêt propre : on tue TOUT le groupe de process ------------------------
|
# Tue récursivement un process et toute sa descendance (enfants, petits-enfants…).
|
||||||
# Comme le script tourne dans sa propre session (setsid), son PID est aussi le PGID.
|
# On remonte les enfants AVANT de tuer le parent pour ne pas perdre la filiation, puis
|
||||||
# `kill -- -$$` envoie le signal à TOUT le groupe (backend, frontend et leurs enfants),
|
# on envoie TERM à chaque PID. Robuste et sans effet sur le terminal (ni set -m ni setsid).
|
||||||
# ce qui libère réellement le port backend. Repli ciblé par sécurité.
|
tuer_arbre() {
|
||||||
cleanup() {
|
local pid="$1"
|
||||||
echo ""
|
[ -z "$pid" ] && return 0
|
||||||
echo "→ Arrêt (groupe de process)…"
|
local enfant
|
||||||
# Signal au groupe entier (le '-' devant le PID = groupe). $$ = PID du script = PGID.
|
for enfant in $(pgrep -P "$pid" 2>/dev/null); do
|
||||||
kill -TERM -- "-$$" 2>/dev/null || true
|
tuer_arbre "$enfant"
|
||||||
# Repli : au cas où certains process ne seraient pas dans le groupe.
|
done
|
||||||
kill "$PID_BACK" "$PID_FRONT" 2>/dev/null || true
|
kill -TERM "$pid" 2>/dev/null || true
|
||||||
pkill -f "SchotzIadKmTracker.Api" 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 ------------------
|
# --- 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.
|
# La première compilation (surtout après vidage du cache) peut prendre 30–60 s.
|
||||||
|
|||||||
Reference in New Issue
Block a user