2012-02-24 5 views
6

Tengo un servidor web donde ejecuto algunos programas de inicio lento como daemons. Estos a veces necesitan un reinicio rápido (o detención) cuando los recompilo o cambie a otra instalación de ellos.Permitir que otros usuarios detengan/reinicien daemons Bash simples: ¿usar señales o qué?

Inspirado por http://mywiki.wooledge.org/ProcessManagement, estoy escribiendo un guión llamada daemonise.sh que se parece a

#!/bin/sh 
while :; do 
    ./myprogram lotsadata.xml 
    echo "Restarting server..." 1>&2 
done 

para mantener un "daemon" corriendo. Desde que a veces es necesario para detenerlo, o simplemente reinicio que, corro esa secuencia de comandos en una sesión de pantalla, como:

$ ./daemonise.sh & DPID=$! 
$ screen -d 

Entonces, tal vez me vuelva a compilar miprograma, instalar a un nuevo camino, empezar el nuevo y quiere matar a la anterior:

$ screen -r 
$ kill $DPID 
$ screen -d 

Esto funciona bien cuando yo soy el único responsable, pero ahora quiere dejar otra persona parada/reinicio del programa, no importa que lo inició. Y para hacer las cosas más complicadas, la secuencia de comandos daemonise.sh de hecho comienza unos 16 programas, por lo que es una molestia matar a todos y cada uno si no conoce sus PID.

¿Cuál sería la forma de "mejores prácticas" para dejar que otro usuario detenga/reinicie los daemons?

Pensé en sesiones de pantalla compartidas, pero eso solo suena a hacky y inseguro. La mejor solución que he llegado con por ahora es envolver de partida y matar en un guión que atrapa ciertas señales:

#!/bin/bash 
DPID= 
trap './daemonise.sh & DPID=$!' USR1 
trap 'kill $DPID' USR2 EXIT 

# Ensure trapper wrapper doesn't exit: 
while :; do 
    sleep 10000 & wait $! 
done 

Ahora, en caso de que otro usuario tenga que detener los demonios y no puedo hacerlo , ella solo tiene que saber el pid del envoltorio, y por ejemplo sudo kill -s USR2 $wrapperpid. (Además, esto permite ejecutar los daemons en los reinicios, y aún así eliminarlos limpiamente).

¿Existe una solución mejor? ¿Hay problemas obvios con esta solución que no estoy viendo?

(Después de leer de Greg Wiki Bash, me gustaría evitar cualquier solución que implica pgrep o PID-archivos ...)

+1

+1 para el enlace de la Wiki de Greg's Bash. ¡Buena suerte! – shellter

+1

archivos pid son la mejor convención – reconbot

+0

@wizard tiene razón. no obtendrás una respuesta que valga la pena porque básicamente dices "sé que la rueda existe, pero quiero inventar la mía". –

Respuesta

1

recomiendo un script de inicio basada PID. Cualquiera con sudo privilegiado para el script podrá iniciar y detener los procesos del servidor.

+1

"basado en PID"? ¿Quiere decir basado en archivos PID? Si voy a permitir que otros usuarios sudo detengan 16 procesos a la vez en un servidor, no quiero arriesgarme a que los PID apunten a los procesos incorrectos. ¿Cómo se aseguraría de que ninguno de los procesos se haya detenido y dado sus PID a otros procesos sin controlarlos desde un padre? – unhammer

+1

Deje que sus programas creen y limpien sus propios archivos pid. Las posibilidades de que un programa falle y se distribuya a otro proceso es bastante bajo (debería abarcar todos los pids disponibles, generalmente un int de 64 bits). Si todavía está preocupado, eche un vistazo a los procesos antes de matarlo. (/ proc/PID/cmdline es una manera fácil.) – reconbot

+1

@wizard: ¿Qué plataforma fue esa? Estoy ejecutando Ubuntu 11.10 de 64 bits, y/proc/sys/kernel/pid_max dice '32768'. Eso * no * toma mucho tiempo para envolver. – l0b0

1

En la mejora de su enfoque: ¿no sería recomendable asegurarse de que su comando sleep en sleep 10000 & wait $! se termine adecuadamente si su script pidwrapper se cierra de alguna manera?

De lo contrario, quedaría un proceso sleep colgando en la tabla de proceso durante bastante tiempo.

Del mismo modo, ¿no sería más limpio de interrumpir myprogram en daemonise.sh correctamente en reinicio (i. E., Si daemonise.sh recibe una señal TERM)?

Además, es posible suprimir mensajes de notificación de trabajo y probar la existencia de pid antes de matar.

#!/bin/sh 
# cat daemonise.sh 

# cf. "How to suppress Terminated message after killing in bash?", 
# http://stackoverflow.com/q/81520 

trap ' 
    echo "server shut down..." 1>&2 
    kill $spid1 $spid2 $spid3 && 
     wait $spid1 $spid2 $spid3 2>/dev/null 
    exit 
' TERM 

while :; do 
    echo "Starting server..." 1>&2 
    #./myprogram lotsadata.xml 
    sleep 100 & 
    spid1=${!} 
    sleep 100 & 
    spid2=${!} 
    sleep 100 & 
    spid3=${!} 
    wait 
    echo "Restarting server..." 1>&2 
done 

#------------------------------------------------------------ 

#!/bin/bash 
# cat pidwrapper 

DPID= 

trap ' 
    kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null 
    ./daemonise.sh & DPID=${!} 
' USR1 

trap ' 
    kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null 
    kill -0 $DPID 2>/dev/null && kill $DPID && wait ${DPID} 2>/dev/null 
' USR2 

trap ' 
    trap - EXIT 
    kill -0 $DPID 2>/dev/null && kill $DPID && wait ${DPID} 2>/dev/null 
    kill -0 ${!} 2>/dev/null && kill ${!} && wait ${!} 2>/dev/null 
    exit 0 
' EXIT 

# Ensure trapper wrapper does not exit: 
while :; do 
    sleep 10000 & wait $! 
done 

#------------------------------------------------------------ 

# test 

{ 
wrapperpid="`exec sh -c './pidwrapper & echo ${!}' | head -1`" 
echo "wrapperpid: $wrapperpid" 
for n in 1 2 3 4 5; do 
    sleep 2 
    # start daemonise.sh 
    kill -s USR1 $wrapperpid 
    sleep 2 
    # kill daemonise.sh 
    kill -s USR2 $wrapperpid 
done 
sleep 2 
echo kill $wrapperpid 
kill $wrapperpid 
} 
+0

Sí ... en realidad prefiero ver lo que ha terminado :-) pero sí que funciona. No había pensado en el proceso de dormir perdido del envoltorio. – unhammer

Cuestiones relacionadas