J'ai un script Bash, qui ressemble à ceci:
#!/bin/bash
echo "Doing some initial work....";
/bin/start/main/server --nodaemon
Maintenant, si le shell bash exécutant le script reçoit un signal SIGTERM, il doit également envoyer un SIGTERM au serveur en cours d'exécution (qui bloque, donc aucun piège possible). Est-ce possible?
Essayer:
#!/bin/bash
_term() {
echo "Caught SIGTERM signal!"
kill -TERM "$child" 2>/dev/null
}
trap _term SIGTERM
echo "Doing some initial work...";
/bin/start/main/server --nodaemon &
child=$!
wait "$child"
Normalement, bash
ignorera tous les signaux pendant l'exécution d'un processus enfant. Démarrage du serveur avec &
le fondera dans le système de contrôle des tâches de Shell, avec $!
contenant le PID du serveur (à utiliser avec wait
et kill
). L'appel de wait
attendra alors que le travail avec le PID spécifié (le serveur) se termine, ou que tout signal soit déclenché.
Lorsque le shell reçoit SIGTERM
(ou que le serveur se ferme indépendamment), l'appel wait
revient (en quittant avec le code de sortie du serveur ou avec le numéro de signal + 128 en cas de réception d'un signal) . Par la suite, si le Shell a reçu SIGTERM, il appellera le _term
fonction spécifiée comme gestionnaire d'interruptions SIGTERM avant de quitter (dans laquelle nous effectuons tout nettoyage et propagons manuellement le signal au processus serveur à l'aide de kill
).
Bash ne transmet pas de signaux comme SIGTERM aux processus qu'il attend actuellement. Si vous souhaitez mettre fin à votre script en enchaînant votre serveur (lui permettant de gérer les signaux et tout le reste, comme si vous aviez démarré le serveur directement), vous devez utiliser exec
, qui remplacera le shell par le processus en cours d'ouverture :
#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon
Si vous devez conserver le shell pour une raison quelconque (c'est-à-dire que vous devez effectuer un nettoyage après la fin du serveur), vous devez utiliser une combinaison de trap
, wait
et kill
. Voir réponse de SensorSmith .
Andreas Veithen souligne que si vous n'avez pas besoin de revenir de l'appel (comme dans l'exemple de l'OP), un simple appel via la commande exec
est suffisant ( @ Stuart P Réponse de Bentley ). Sinon, le "traditionnel" trap 'kill $CHILDPID' TERM
(réponse de @ cuonglm) est un début, mais l'appel wait
revient en fait après l'exécution du gestionnaire d'interruptions, ce qui peut être encore avant la fin du processus enfant. Un appel "supplémentaire" à wait
est donc conseillé ( réponse de @ user1463361 ).
Bien qu'il s'agisse d'une amélioration, il a toujours une condition de concurrence critique qui signifie que le processus peut ne jamais se terminer (à moins que le signaleur ne réessaye d'envoyer le signal TERM). La fenêtre de vulnérabilité se situe entre l'enregistrement du gestionnaire d'interruptions et l'enregistrement du PID de l'enfant.
Ce qui suit élimine cette vulnérabilité (emballé dans des fonctions à réutiliser).
prep_term()
{
unset term_child_pid
unset term_kill_needed
trap 'handle_term' TERM INT
}
handle_term()
{
if [ "${term_child_pid}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
else
term_kill_needed="yes"
fi
}
wait_term()
{
term_child_pid=$!
if [ "${term_kill_needed}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
fi
wait ${term_child_pid}
trap - TERM INT
wait ${term_child_pid}
}
# EXAMPLE USAGE
prep_term
/bin/something &
wait_term
La solution fournie ne fonctionne pas pour moi car le processus a été tué avant la fin de la commande d'attente. J'ai trouvé cet article http://veithen.github.io/2014/11/16/sigterm-propagation.html , le dernier extrait de code fonctionne bien dans mon cas d'application démarrée dans OpenShift avec sh personnalisé coureur. Le script sh est requis car j'ai besoin d'avoir la possibilité d'obtenir des vidages de threads, ce qui est impossible dans le cas où le PID de Java process is 1.
trap 'kill -TERM $PID' TERM INT
$Java_EXECUTABLE $Java_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?