scripts script resueltos programas programacion pasar parametros español ejercicios ejemplos bash scripting cron

resueltos - ¿Cómo escribo un script de bash para reiniciar un proceso si muere?



scripts linux ejercicios resueltos (7)

Debe usar monit, una herramienta estándar de Unix que puede monitorear diferentes cosas en el sistema y reaccionar en consecuencia.

De los documentos: http://mmonit.com/monit/documentation/monit.html#pid_testing

check process checkqueue.py with pidfile /var/run/checkqueue.pid if changed pid then exec "checkqueue_restart.sh"

También puede configurar monit para que le envíe un correo electrónico cuando se reinicie.

Tengo un script de Python que revisará una cola y realizará una acción en cada elemento:

# checkqueue.py while True: check_queue() do_something()

¿Cómo escribo un script bash que verifique si se está ejecutando y, si no, lo inicia? Aproximadamente el siguiente pseudo código (o quizás debería hacer algo como ps | grep ?):

# keepalivescript.sh if processidfile exists: if processid is running: exit, all ok run checkqueue.py write processid to processidfile

Llamaré a eso desde un crontab:

# crontab */5 * * * * /path/to/keepalivescript.sh


Echa un vistazo a monit ( http://mmonit.com/monit/ ). Maneja el inicio, la detención y el reinicio de su script y puede realizar comprobaciones de estado y reiniciar si es necesario.

O haz un simple script:

while true do /your/script sleep 1 done


Evite archivos PID, crons o cualquier otra cosa que intente evaluar procesos que no son sus hijos.

Hay una muy buena razón por la que en UNIX, SOLO puede esperar a sus hijos. Cualquier método (ps parsing, pgrep, almacenamiento de un PID, ...) que intente evitarlo es defectuoso y tiene agujeros. Sólo di que no .

En su lugar, necesita que el proceso que supervisa su proceso sea el padre del proceso. ¿Qué significa esto? Significa que solo el proceso que inicia su proceso puede esperar de manera confiable a que finalice. En bash, esto es absolutamente trivial.

until myserver; do echo "Server ''myserver'' crashed with exit code $?. Respawning.." >&2 sleep 1 done

La parte anterior del código bash ejecuta myserver en un bucle until . La primera línea inicia myserver y espera a que finalice. Cuando termina, until compruebe su estado de salida. Si el estado de salida es 0 , significa que terminó con gracia (lo que significa que le pidió que cerrara de alguna manera, y lo hizo con éxito). En ese caso, no queremos reiniciarlo (¡solo le pedimos que se apague!). Si el estado de salida no es 0 , until se ejecute el cuerpo del bucle, se emite un mensaje de error en STDERR y se reinicia el bucle (de nuevo a la línea 1) después de 1 segundo .

¿Por qué esperamos un segundo? Porque si algo está mal con la secuencia de inicio de myserver y se bloquea de inmediato, tendrá un bucle muy intenso de reinicios y bloqueos constantes en sus manos. El sleep 1 quita la tensión de eso.

Ahora todo lo que necesita hacer es iniciar este script de bash (de forma asíncrona, probablemente), y supervisará myserver y lo reiniciará según sea necesario. Si desea iniciar el monitor durante el inicio (haciendo que el servidor "sobreviva" se reinicie), puede programarlo en el cron (1) de su usuario con una regla @reboot . Abre tus reglas cron con crontab :

crontab -e

Luego, agregue una regla para iniciar su script de monitor:

@reboot /usr/local/bin/myservermonitor

Alternativamente; mire inittab (5) y / etc / inittab. Puede agregar una línea allí para que myserver comience en un cierto nivel de inicio y reaparezca automáticamente.

Editar.

Permítanme agregar alguna información sobre por qué no usar archivos PID. Si bien son muy populares; también son muy defectuosos y no hay razón para que no lo hagas de la manera correcta.

Considera esto:

  1. Reciclaje de PID (matando el proceso equivocado):

    • /etc/init.d/foo start : start foo , escribe el PID de foo en /var/run/foo.pid
    • Un rato después: foo muere de alguna manera.
    • Un rato después: cualquier proceso aleatorio que se inicie (llámelo bar ) toma un PID aleatorio, imagínelo tomando el PID antiguo de foo .
    • Observa que foo ha ido: /etc/init.d/foo/restart lee /var/run/foo.pid , comprueba si sigue vivo, encuentra bar , cree que es foo , lo mata, comienza un nuevo foo .
  2. Los archivos PID quedan obsoletos. Necesita una lógica demasiado complicada (o debería decir, no trivial) para comprobar si el archivo PID está obsoleto y si una lógica de este tipo es vulnerable de nuevo a 1. ..

  3. ¿Qué sucede si ni siquiera tiene acceso de escritura o está en un entorno de solo lectura?

  4. Es una excesiva complicación sin sentido; mira lo sencillo que es mi ejemplo anterior. No hay necesidad de complicar eso, en absoluto.

Vea también: ¿Son los archivos PID todavía defectuosos cuando lo hacen ''correcto''?

Por cierto; incluso peor que los archivos PID está analizando ps ! Nunca hagas esto.

  1. ps es muy inportable. Mientras lo encuentras en casi todos los sistemas UNIX; sus argumentos varían mucho si quieres una salida no estándar. ¡Y la salida estándar es SOLO para consumo humano, no para análisis de secuencias de comandos!
  2. Parsing ps conduce a un montón de falsos positivos. Toma el ps aux | grep PID Ejemplo de ps aux | grep PID , y ahora imagina que alguien comienza un proceso con un número en algún lugar como argumento que resulta ser el mismo que el PID con el que miraste a tu demonio. Imagina a dos personas comenzando una sesión de X y grepping para que X mate la tuya. Es todo tipo de cosas malas.

Si no quieres gestionar el proceso por ti mismo; Hay algunos sistemas perfectamente buenos que actuarán como monitores de sus procesos. Mira en runit , por ejemplo.


He utilizado el siguiente script con gran éxito en numerosos servidores:

pid=`jps -v | grep $INSTALLATION | awk ''{print $1}''` echo $INSTALLATION found at PID $pid while [ -e /proc/$pid ]; do sleep 0.1; done

notas:

  • Está buscando un proceso java, así que puedo usar jps, esto es mucho más consistente en todas las distribuciones que ps
  • $INSTALLATION contiene suficiente de la ruta del proceso que es totalmente inequívoca
  • Duerma mientras espera que el proceso muera, evite acaparar recursos :)

Esta secuencia de comandos se usa realmente para cerrar una instancia en ejecución de Tomcat, que quiero cerrar (y esperar) en la línea de comandos, por lo que lanzarla como un proceso secundario simplemente no es una opción para mí.


La forma más fácil de hacerlo es usar flock on file. En script Python harías

lf = open(''/tmp/script.lock'',''w'') if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0): sys.exit(''other instance already running'') lf.write(''%d/n''%os.getpid()) lf.flush()

En shell puedes probar si está funcionando:

if [ `flock -xn /tmp/script.lock -c ''echo 1''` ]; then echo ''it''s not running'' restart. else echo -n ''it''s already running with PID '' cat /tmp/script.lock fi

Pero, por supuesto, no tiene que hacer una prueba, porque si ya se está ejecutando y reinicia, saldrá con ''other instance already running''

Cuando el proceso muere, todos sus descriptores de archivo se cierran y todos los bloqueos se eliminan automáticamente.


No estoy seguro de cuán portátil es en los sistemas operativos, pero puede verificar si su sistema contiene el comando ''run-one'', es decir, "man run-one". Específicamente, este conjunto de comandos incluye ''ejecutar-uno-constantemente'', que parece ser exactamente lo que se necesita.

De la página del manual:

run-one-constant COMMAND [ARGS]

Nota: obviamente esto podría llamarse desde su script, pero también elimina la necesidad de tener un script.


if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then restart_process # Write PIDFILE echo $! >$PIDFILE fi