Comment redémarrer automatiquement un processus d'arrière-plan Linux en cas d'échec?

32

J'ai un processus qui est exécuté par le script init.d en arrière-plan. Par exemple:

case "$1" in 
    start)
       /bin/myprocess &
    stop)
       killall myprocess
    restart)
       killall myprocess
       /bin/myprocess &
esac

Dans certaines conditions, myprocess peut échouer et revenir. Existe-t-il un moyen (standard) de détecter son échec et de redémarrer automatiquement?

Honza
la source
Bien sûr, mais cela varie en fonction de la distribution. Presque tous fournissent une sorte de gestionnaire de services.
David Schwartz
Il n'y a pas de distribution standard, mais buildroot. Je dois donc le faire manuellement ...
Honza

Réponses:

14

Le moyen le plus simple serait de l'ajouter à / etc / inittab , qui est conçu pour faire ce genre de chose:

respawn Si le processus n'existe pas, démarrez-le. N'attendez pas sa fin (continuez à scanner le fichier / etc / inittab). Redémarrez le processus lorsqu'il meurt. Si le processus existe, ne faites rien et continuez à analyser le fichier / etc / inittab.

Par exemple, vous pouvez faire ceci:

# Run my stuff
myprocess:2345:respawn:/bin/myprocess
Alan Shutko
la source
Remarque, /etc/inittabfonctionne (ou existe même) si et seulement si vous avez un système d'initialisation basé sur Sysvinit. Avec upstart et avec systemd, ce n'est pas le cas. Vous devez installer soit busybox (shell très primitif rendant les tâches de récupération de sysadm pénibles, mais il peut remplacer un initd compatible avec sysvinit) ou sysvinit (c'est un fossile). Dans un container docker, seul le premier n'est pas douloureux.
peterh dit réintégrer Monica le
27

Buildroot a trois systèmes d'initialisation possibles, il y a donc trois façons de procéder:

BusyBox init

Avec cela, on ajoute une entrée à /etc/inittab.

::respawn:/bin/myprocess

Notez que BusyBox inita un /etc/inittabformat idiosyncratique . Le deuxième champ n'a pas de sens et le premier champ n'est pas un ID mais un nom de base de périphérique.

Linux "System V" init

Encore une fois, on ajoute une entrée à /etc/inittab.

myprocess:2345:respawn:/bin/myprocess

systemd

On écrit un fichier unitaire dans, disons /etc/systemd/system/myprocess.service:

[Unit]
Description=My Process

[Service]
ExecStart=/bin/myprocess
Restart=always

[Install]
WantedBy=multi-user.target

Activez cette option pour démarrer automatiquement au démarrage avec:

systemctl enable myprocess.service

Démarrez-le manuellement avec:

systemctl start myprocess.service

Lectures complémentaires

JdeBP
la source
mais lorsque vous utilisez cette approche inittab, votre processus n'est plus accessible via l'interface «service», n'est-ce pas? c'est-à-dire que vous ne pouvez pas y aller service mything startou service mything stopplus .... est-il possible d'avoir le meilleur des deux? c'est-à-dire un service sysvinit non effaçable, mais aussi l'avoir utilisable via 'service'?
horseyguy
25

Qu'en est-il de la création d'un sous-shell avec une boucle qui appelle constamment le même processus?

S'il se termine, l'itération suivante de la boucle continue et la redémarre.

(while true; do 
    /bin/myprocess
done) &

Si le sous-shell meurt, c'est fini. La seule possibilité dans ce cas serait de créer un autre processus (je l'appellerai nécromancien) qui vérifie si votre processus est vivant, le démarre s'il ne l'est pas et exécute ce nécromancien avec cron, afin que vous puissiez le vérifier régulièrement.

La prochaine étape serait de se demander ce qui pourrait arriver si Cron meurt, mais à un moment donné, vous devriez vous sentir en sécurité et cesser de vous inquiéter.

Trylks
la source
3

Vous pouvez utiliser Monit . C'est vraiment facile à utiliser et assez flexible. Voir par exemple cette configuration pour redémarrer le processus Tomcat en cas d'échec.

check process tomcat with pidfile /var/run/tomcat.pid
   start program = "/etc/init.d/tomcat start"
   stop  program = "/etc/init.d/tomcat stop"
   if failed port 8080 type tcp then restart

Il contient également de nombreux exemples de configuration pour de nombreux cas d'utilisation.

Clyde D'Cruz
la source
1

Si vous n'êtes pas un super utilisateur ou un super-utilisateur, et si Docker est installé sur votre système Linux, vous pouvez créer une image docker de votre processus, en utilisant docker pour redémarrer votre processus si le système est redémarré.

Fichier: docker-compose.yml

version: "3"
services:
  lserver:
    image: your_docker_image:latest
    ports:
    - 8080:8080   # just use 8080 as an example
    restart: always  # this is where your process can be guaranteed to restart

Pour démarrer votre conteneur Docker,

docker-compose up -d

Je trouve qu'il est facile de gérer mon propre processus avec un redémarrage automatique si je ne suis pas un super utilisateur du système.

Pour un exemple d'exemple de création d'une image Docker, voici un exemple rapide:

Fichier: Dockerfile

FROM alpine:3.5

RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
WORKDIR /app
COPY my-process-server /app
RUN ln -s /app/my-process-server /usr/local/bin/my-process-server

EXPOSE 8080

CMD ["my-process-server"]
Michael Qin
la source
0

Dans mon cas, comme solution rapide, j'ai modifié et utilisé la solution de @Trylks pour envelopper le programme que je lançais. Je voulais que cela se termine uniquement sur une sortie propre.

Devrait fonctionner dans la plupart des obus:

#!/bin/sh

echo ""
echo "Use: $0 ./program"
echo ""

#eg="/usr/bin/apt update"

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done) &
user9869932
la source
0

Vous pouvez utiliser le redémarrage

start)
   restarter -c /bin/myprocess &
stop)
   pkill -f myprocess

Sur les systèmes plus récents, utilisez systemd qui résout tous ces problèmes triviaux

sivann
la source