¿Cómo reiniciar automáticamente un proceso de fondo de Linux si falla?

32

Tengo un proceso que se ejecuta mediante el script init.d en segundo plano. P.ej:

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

En ciertas condiciones, mi proceso puede fallar y regresar. ¿Hay alguna forma (estándar) de cómo detectar su falla y reiniciar automáticamente?

Honza
fuente
Claro, pero varía según la distribución. Casi todos ellos ofrecen algún tipo de administrador de servicios.
David Schwartz
No hay una distribución estándar, sino buildroot. Así que tengo que hacerlo manualmente ...
Honza

Respuestas:

14

La forma más fácil sería agregarlo a / etc / inittab , que está diseñado para hacer este tipo de cosas:

reaparecer Si el proceso no existe, inicie el proceso. No espere a que termine (continúe escaneando el archivo / etc / inittab). Reinicie el proceso cuando muera. Si el proceso existe, no haga nada y continúe escaneando el archivo / etc / inittab.

Por ejemplo, podrías hacer esto:

# Run my stuff
myprocess:2345:respawn:/bin/myprocess
Alan Shutko
fuente
Tenga en cuenta que /etc/inittabfunciona (o incluso existe) si y solo si tiene un sistema de inicio basado en sysvinit. Con advenedizo y con systemd no lo hace. Debe instalar busybox (shell muy primitivo que hace que el sysadm recupere tareas dolorosas, pero puede sustituir a un initd compatible con sysvinit) o sysvinit (es un fósil). En un contenedor acoplable, solo el primero no es doloroso.
Peter dice reinstalar a Mónica el
27

Buildroot tiene tres posibles sistemas de inicio, por lo que hay tres formas de hacerlo:

BusyBox init

Con esto, uno agrega una entrada a /etc/inittab.

::respawn:/bin/myprocess

Tenga en cuenta que BusyBox inittiene un /etc/inittabformato idiosincrásico . El segundo campo no tiene sentido y el primer campo no es una ID. sino un nombre base del dispositivo.

Linux "Sistema V" init

De nuevo, uno agrega una entrada a /etc/inittab.

myprocess:2345:respawn:/bin/myprocess

systemd

Uno escribe un archivo de unidad en, digamos /etc/systemd/system/myprocess.service,:

[Unit]
Description=My Process

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

[Install]
WantedBy=multi-user.target

Habilite esto para iniciar automáticamente en el arranque con:

systemctl enable myprocess.service

Comience manualmente con:

systemctl start myprocess.service

Otras lecturas

JdeBP
fuente
pero cuando usa este enfoque inittab, entonces su proceso ya no es accesible a través de la interfaz de 'servicio' ¿verdad? es decir, no puedes ir service mything starto service mything stopmás ... ¿hay alguna manera de tener lo mejor de ambos? es decir, servicio sysvinit no rompible, pero ¿también se puede usar a través del 'servicio'?
horseyguy
25

¿Qué hay de crear una subshell con un bucle que invoca constantemente el mismo proceso?

Si termina, la siguiente iteración del bucle continúa y comienza de nuevo.

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

Si la subshell muere, se acabó. La única posibilidad en ese caso sería crear otro proceso (lo llamaré nigromante) que verifica si su proceso está vivo, iniciarlo si no lo está y ejecutar este nigromante con cron, para que pueda verificarlo regularmente.

El siguiente paso sería preguntarse qué podría pasar si cron muere, pero en algún momento debería sentirse seguro y dejar de preocuparse.

Trylks
fuente
3

Podrías hacer uso de Monit . Es realmente fácil de usar y bastante flexible. Consulte, por ejemplo, esta configuración para reiniciar el proceso de Tomcat en caso de falla.

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

También tiene muchos ejemplos de configuración para muchos casos de uso.

Clyde D'Cruz
fuente
1

Si no es un superusuario o root, y si su sistema Linux tiene Docker instalado, puede crear una imagen de Docker de su proceso, utilizando Docker para reiniciar su proceso si el sistema se reinicia.

Archivo: 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

Para iniciar su contenedor acoplable,

docker-compose up -d

Creo que es fácil manejar mi propio proceso con reinicio automático si no soy un superusuario del sistema.

Para un ejemplo de ejemplo de cómo crear una imagen acoplable, aquí hay un ejemplo rápido:

Archivo: 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
fuente
0

En mi caso, como solución rápida, modifiqué y utilicé la solución de @ Trylks para envolver el programa que estaba iniciando. Quería que terminara solo en una salida limpia.

Debería ejecutarse en la mayoría de los depósitos:

#!/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) &
usuario9869932
fuente
0

Puedes usar el reiniciador

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

En los sistemas más nuevos, use systemd que resuelve todos esos problemas triviales

sivann
fuente