Me gustaría un daemonizer que pueda convertir un script o comando genérico y arbitrario en un daemon .
Hay dos casos comunes con los que me gustaría tratar:
Tengo un script que debería ejecutarse para siempre. Si alguna vez muere (o al reiniciar), reinícielo. No permita que nunca haya dos copias ejecutándose a la vez (detecte si una copia ya se está ejecutando y no la inicie en ese caso).
Tengo un script simple o un comando de línea de comando que me gustaría seguir ejecutando repetidamente para siempre (con una breve pausa entre ejecuciones). Nuevamente, no permita que dos copias del script se ejecuten a la vez.
Por supuesto, es trivial escribir un bucle "while (verdadero)" alrededor del script en el caso 2 y luego aplicar una solución para el caso 1, pero una solución más general simplemente resolverá el caso 2 directamente, ya que se aplica al script en el caso 1 como así (puede que sólo quieren una más corta o ninguna pausa si el guión no está destinado a morir nunca (por supuesto, si el guión realmente no nunca mueren después de la pausa en realidad no importa)).
Tenga en cuenta que la solución no debería implicar, por ejemplo, agregar código de bloqueo de archivos o grabación PID a los scripts existentes.
Más específicamente, me gustaría un programa "demonizar" que pueda ejecutar como
% daemonize myscript arg1 arg2
o, por ejemplo,
% daemonize 'echo `date` >> /tmp/times.txt'
que mantendría una lista creciente de fechas adjuntas a times.txt. (Tenga en cuenta que si el (los) argumento (s) para demonizar es un script que se ejecuta para siempre como en el caso 1 anterior, entonces demonizar seguirá haciendo lo correcto, reiniciándolo cuando sea necesario). Entonces podría poner un comando como el anterior en mi .login y / o cron cada hora o cada minuto (dependiendo de cuán preocupado estaba de que muriera inesperadamente).
NB: El script daemonize necesitará recordar la cadena de comando que está demonizando para que si la misma cadena de comando es demonizada nuevamente, no lance una segunda copia.
Además, la solución idealmente debería funcionar tanto en OS X como en Linux, pero las soluciones para uno u otro son bienvenidas.
EDITAR: Está bien si tiene que invocarlo con sudo daemonize myscript myargs
.
(Si estoy pensando en todo esto mal o si hay soluciones parciales rápidas y sucias, también me encantaría escuchar eso).
PD: En caso de que sea útil, aquí hay una pregunta similar específica para Python.
Y esta respuesta a una pregunta similar tiene lo que parece ser un idioma útil para una demonización rápida y sucia de un guión arbitrario:
Respuestas:
Puede demonizar cualquier ejecutable en Unix usando nohup y el operador &:
El comando nohup le permite cerrar su sesión de shell sin que mate su script, mientras que & coloca su script en segundo plano para que obtenga un indicador de shell para continuar su sesión. El único problema menor con esto es la salida estándar y el error estándar se envían a ./nohup.out, por lo que si inicia varios scripts en esta mansión, su salida se entrelazará. Un mejor comando sería:
Esto enviará el estándar al archivo de su elección y el error estándar a un archivo diferente de su elección. Si desea usar solo un archivo para la salida estándar y el error estándar, puede usar esto:
El 2> & 1 le dice al shell que redirija el error estándar (descriptor de archivo 2) al mismo archivo que la salida estándar (descriptor de archivo 1).
Para ejecutar un comando solo una vez y reiniciarlo si muere, puede usar este script:
El primer argumento es el nombre del archivo pid a utilizar. El segundo argumento es el comando. Y todos los demás argumentos son los argumentos del comando.
Si le asigna un nombre a este script restart.sh, así es como lo llamaría:
fuente
trap EXIT
)<
entest
es una comparación ASCII, no una comparación de números enteros. Puede que aún funcione, pero puede provocar errores.Pido disculpas por la respuesta larga (consulte los comentarios sobre cómo mi respuesta cumple con las especificaciones). Estoy tratando de ser comprensivo, para que tengas la mejor ventaja posible. :-)
Si puede instalar programas (tiene acceso de root) y está dispuesto a hacer un trabajo de campo único para configurar su script para la ejecución del demonio (es decir, más complicado que simplemente especificar los argumentos de la línea de comandos para ejecutar en la línea de comandos, pero solo debe hacerse una vez por servicio), tengo una forma que es más sólida.
Implica el uso de daemontools . El resto de la publicación describe cómo configurar servicios usando daemontools.
Configuración inicial
/service
. El instalador ya debería haber hecho esto, pero solo verifique, o si está instalando manualmente. Si no le gusta esta ubicación, puede cambiarla en susvscanboot
script, aunque la mayoría de los usuarios de daemontools están acostumbrados a usar/service
y se confundirán si no la usa.init
(es decir, no usa/etc/inittab
), necesitará usar el preinstaladoinittab
como base para organizar lasvscanboot
llamadainit
. No es difícil, pero necesita saber cómo configurar elinit
que usa su sistema operativo.svscanboot
es un script que llamasvscan
, que hace el trabajo principal de buscar servicios; se llama desde,init
por lo queinit
se encargará de reiniciarlo si muere por cualquier motivo.Configuración por servicio
/var/lib/svscan
, pero cualquier nueva ubicación estará bien.Yo suelo usar una secuencia de comandos para configurar el directorio de servicios, para ahorrar una gran cantidad de trabajo manual repetitivo. p.ej,
donde
some-service-name
es el nombre que desea dar a su servicio,user
es el usuario con el que ejecutará ese servicio yloguser
es el usuario con el que ejecutará el registrador. (El registro se explica brevemente).fghack
, aunque esto tiene una compensación: ya no puede controlar el uso del programasvc
.run
secuencia de comandos para asegurarse de que esté haciendo lo que desea. Puede que tenga que colocar unasleep
llamada en la parte superior, si espera que su servicio a la salida con frecuencia./service
apunte a su directorio de servicios. (No coloque directorios de servicios directamente dentro/service
; hace que sea más difícil eliminar el servicio delsvscan
reloj)Inicio sesión
mkservice
);svscan
se encarga de enviar mensajes de registro al servicio de registro.mkservice
creará archivos de registro con marca de tiempo y rotación automática en ellog/main
directorio. Se llama al archivo de registro actualcurrent
.tai64nlocal
traducirá las marcas de tiempo a un formato legible por humanos. (TAI64N es una marca de tiempo atómica de 64 bits con una cuenta de nanosegundos).Servicios de control
svstat
para obtener el estado de un servicio. Tenga en cuenta que el servicio de registro es independiente y tiene su propio estado.svc
. Por ejemplo, para reiniciar su servicio, usesvc -t /service/some-service-name
;-t
significa "enviarSIGTERM
".-h
(SIGHUP
),-a
(SIGALRM
),-1
(SIGUSR1
),-2
(SIGUSR2
) y-k
(SIGKILL
).-d
. También puede evitar que un servicio se inicie automáticamente en el arranque creando un archivo con el nombredown
en el directorio de servicios.-u
. Esto no es necesario a menos que lo haya bajado previamente (o lo haya configurado para que no se inicie automáticamente).-x
; también se utiliza normalmente con-d
para finalizar el servicio. Esta es la forma habitual de permitir la eliminación de un servicio, pero/service
primero debe desvincular el servicio o, de lo contrariosvscan
, reiniciará el supervisor. Además, si creó su servicio con un servicio de registro (mkservice -l
), recuerde también salir del supervisor de registro (por ejemplo,svc -dx /var/lib/svscan/some-service-name/log
) antes de eliminar el directorio de servicios.Resumen
Pros:
init
proporciona.Contras:
svc
y no puede ejecutar los scripts de ejecución directamente (ya que entonces no estarían bajo el control del supervisor).supervise
procesos en su tabla de procesos.)En resumen, creo que daemontools es un sistema excelente para sus necesidades. Agradezco cualquier pregunta sobre cómo configurarlo y mantenerlo.
fuente
supervise
, el supervisor, se encarga de reiniciar cualquier servicio que salga. Espera un segundo entre reinicios; si no es suficiente tiempo para usted, ponga en suspensión en la parte superior del script de ejecución del servicio.supervise
está respaldado por sí mismosvscan
, por lo que si un supervisor muere, se reiniciará. 2b.svscan
está respaldado porinit
, que se reiniciará automáticamentesvscan
según sea necesario. 2c. Siinit
mueres por alguna razón, estás jodido de todos modos. :-Psvstat
y con los quesvc
pueden trabajar.Creo que quizás quieras intentarlo
start-stop-daemon(8)
. Consulte los scripts en/etc/init.d
cualquier distribución de Linux para ver ejemplos. Puede encontrar procesos iniciados mediante la invocación de la línea de comandos o el archivo PID, por lo que cumple con todos sus requisitos, excepto como un perro guardián para su script. Pero siempre puede iniciar otro script de vigilancia de demonios que simplemente reinicie su script si es necesario.fuente
start-stop-daemon
, tampoco (a partir de 10.9).start-stop-daemon
Sin embargo, todavía está vivo y coleando en Linux; pero después de leer la respuesta stackoverflow.com/a/525406/45375 me di cuenta que OSX hace su propia cosa:launchd
.Debería echar un vistazo a daemonize . Permite detectar una segunda copia (pero utiliza un mecanismo de bloqueo de archivos). También funciona en diferentes distribuciones de UNIX y Linux.
Si necesita iniciar automáticamente su aplicación como demonio, entonces necesita crear un script de inicio apropiado.
Puede utilizar la siguiente plantilla:
fuente
killproc
en la parte de detención: si tuvieras un proceso que, digamos, se ejecutójava
, tambiénkillproc
se eliminarán todos los demás procesos de Java.$corelimit >/dev/null 2>&1 ; $*
Así que dudo que vaya a demonizar algo ...Como alternativa a lo ya mencionado
daemonize
ydaemontools
, existe el comando daemon del paquete libslack.daemon
es bastante configurable y se preocupa por todas las cosas tediosas del demonio, como el reinicio automático, el registro o el manejo de archivos pid.fuente
Si estás usando OS X específicamente, te sugiero que eches un vistazo a cómo funciona launchd. Verificará automáticamente que su script se esté ejecutando y lo reiniciará si es necesario. También incluye todo tipo de funciones de programación, etc. Debe satisfacer tanto el requisito 1 como el 2.
En cuanto a garantizar que solo se pueda ejecutar una copia de su secuencia de comandos, debe utilizar un archivo PID. Generalmente escribo un archivo en /var/run/.pid que contiene un PID de la instancia en ejecución actual. si el archivo existe cuando se ejecuta el programa, comprueba si el PID del archivo se está ejecutando realmente (es posible que el programa se haya bloqueado o se haya olvidado de eliminar el archivo PID). Si es así, aborta. De lo contrario, comience a ejecutar y sobrescriba el archivo PID.
fuente
Daemontools ( http://cr.yp.to/daemontools.html ) es un conjunto de utilidades bastante complejas que se utilizan para hacer esto, escritas por dj bernstein. He usado esto con cierto éxito. La parte molesta de esto es que ninguno de los scripts devuelve resultados visibles cuando los ejecuta, solo códigos de retorno invisibles. Pero una vez que funciona, es a prueba de balas.
fuente
Primero obtenga
createDaemon()
de http://code.activestate.com/recipes/278731/Entonces el código principal:
fuente
Esta es una versión funcional completa con un ejemplo que puede copiar en un directorio vacío y probar (después de instalar las dependencias de CPAN, que son Getopt :: Long , File :: Spec , File :: Pid e IPC :: System: : Simple : todo bastante estándar y muy recomendado para cualquier hacker: puede instalarlos todos a la vez con
cpan <modulename> <modulename> ...
).keepAlive.pl:
ejemplo.pl:
Ahora puede invocar el ejemplo anterior con:
./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3
y sepidfile
creará el archivo y verá el resultado:fuente
También puede probar Monit . Monit es un servicio que monitorea e informa sobre otros servicios. Si bien se usa principalmente como una forma de notificar (por correo electrónico y sms) sobre problemas de tiempo de ejecución, también puede hacer lo que la mayoría de las otras sugerencias aquí han recomendado. Puede auto (re) iniciar y detener programas, enviar correos electrónicos, iniciar otros scripts y mantener un registro de salida que puede recoger. Además, descubrí que es fácil de instalar y mantener, ya que hay documentación sólida.
fuente
Podrías intentar inmortal. Es un supervisor multiplataforma * nix (independiente del sistema operativo).
Para una prueba rápida en macOS:
En caso de que esté usando FreeBSD desde los puertos o usando pkg:
Para Linux descargando los binarios precompilados o desde la fuente: https://immortal.run/source/
Puedes usarlo así:
O mediante un archivo YAML de configuración que le brinda más opciones, por ejemplo:
Si desea mantener también la salida de error estándar en un archivo separado, puede usar algo como:
fuente
He realizado una serie de mejoras en la otra respuesta .
sleep
)-h
eval
, por lo que puede construir cualquier tipo de script de shell como una cadena para enviar a este script como último argumento (o argumentos finales) para que se demonice-lt
lugar de<
Aquí está el guión:
Uso:
Tenga en cuenta que si ejecuta este script desde diferentes directorios, puede usar diferentes archivos pid y no detectar ninguna instancia en ejecución existente. Dado que está diseñado para ejecutar y reiniciar comandos efímeros proporcionados a través de un argumento, no hay forma de saber si algo ya se inició, porque ¿quién puede decir si es el mismo comando o no? Para mejorar esta aplicación de ejecutar solo una instancia de algo, se requiere una solución específica para la situación.
Además, para que funcione como un demonio adecuado, debe usar (como mínimo) nohup como menciona la otra respuesta. No he hecho ningún esfuerzo por proporcionar resistencia a las señales que pueda recibir el proceso.
Un punto más a tener en cuenta es que matar este guión (si fue llamado desde otro guión que se mata, o con una señal) puede no tener éxito en matar al niño, especialmente si el niño es otro guión. No estoy seguro de por qué es así, pero parece ser algo relacionado con la forma en que
eval
funciona, lo cual me resulta misterioso. Por lo tanto, puede ser prudente reemplazar esa línea con algo que acepte solo un comando como en la otra respuesta.fuente