Pregunta

Me gustaría un daemonizer que puede convertir una, secuencia de comandos o un comando genérico arbitraria en un daemon.

Hay dos casos comunes que me gustaría tratar con:

  1. Tengo un script que se debe ejecutar siempre. Si alguna vez se muere (o en el reinicio), reiniciarlo. No permita que alguna vez sean dos copias que se ejecutan a la vez (si detectan una copia ya se está ejecutando y no se ejecutan en ese caso).

  2. Tengo un simple comando script o comando de línea que me gustaría mantener ejecutar repetidamente para siempre (con una breve pausa entre las corridas). Una vez más, no permita que dos copias de la secuencia de comandos para siempre estar en ejecución a la vez.

Por supuesto que es trivial para escribir una "while (true)" bucle alrededor de la secuencia de comandos en el caso 2 y luego aplicar una solución para el caso 1, pero una solución más general se acaba de resolver el caso 2 directamente desde el que se aplica a la secuencia de comandos en 1 caso 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 ¿tiene nunca mueren después de la pausa en realidad no importa)) .

Tenga en cuenta que la solución no debe implicar, por ejemplo, la adición de código de bloqueo de archivos o grabación PID para las secuencias de comandos existentes.

Más específicamente, me gustaría una "daemonize" programa que se puede ejecutar como

% daemonize myscript arg1 arg2

o, por ejemplo,

% daemonize 'echo `date` >> /tmp/times.txt'

lo que mantendría una creciente lista de fechas adjuntas a times.txt. (Tenga en cuenta que si el argumento (s) que en demonio es un script que se ejecuta siempre, como en el caso 1 anterior, a continuación daemonize se siguen haciendo lo correcto, cuando sea necesario reiniciar.) Entonces podría poner un comando como más arriba en mi .login y / o que cron por hora o minuciosamente (dependiendo de lo preocupada que estaba a punto de morir que de forma inesperada).

Nota:. El guión daemonize tendrá que recordar la cadena de comandos se daemonizing de modo que si se endemoniada la misma cadena de comandos de nuevo no se inicia una segunda copia

Además, la solución ideal sería trabajar en ambos OS X y Linux, pero las soluciones para uno o el otro son bienvenidos.

EDIT:. Está muy bien si usted tiene que invocar con sudo daemonize myscript myargs

(Si estoy pensando en esto todo mal o hay soluciones parciales rápida y sucia-, me gustaría saber eso también.)


PD: En caso de que sea útil, aquí está un pregunta similar específica a pitón.

y esta responder a una pregunta similar tiene lo que parece ser un lenguaje útil para una demonización rápido y sucio de un script arbitrario:

¿Fue útil?

Solución

Puede demonizar cualquier ejecutable en Unix usando nohup y el operador &:

nohup yourScript.sh script args&

El comando nohup le permite apagar su sesión de shell sin él matando a su guión, mientras que el coloca y su secuencia de comandos en segundo plano para que pueda obtener un intérprete de comandos para continuar con la sesión. El único problema con esto es la salida estándar y el error estándar tanto son enviadas a ./nohup.out, por lo que si se inicia varios guiones en esta casa se entrelaza su producción. Una mejor comando sería:

nohup yourScript.sh script args >script.out 2>script.error&

Esto enviará la salida estándar al archivo de su elección y el error estándar a un archivo diferente de su elección. Si desea utilizar un solo archivo, tanto para el error estándar y estándar puede nosotros esto:

nohup yourScript.sh script args >script.out 2>&1 &

El 2> & 1 cuenta la cáscara para redirigir error estándar (descriptor de fichero 2) para el mismo archivo como salida estándar (descriptor de archivo 1).

Para ejecutar un comando sólo una vez y reiniciarlo si muere puede utilizar este script:

#!/bin/bash

if [[ $# < 1 ]]; then
    echo "Name of pid file not given."
    exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
    echo "No command given."
    exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
    ps -p $PID >/dev/null 2>&1
    if [[ $? = 0 ]]; then
        echo "Command $1 already running."
        exit
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
    $COMMAND "$@"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

El primer argumento es el nombre del archivo pid de usar. El segundo argumento es el comando. Y todos los demás argumentos son los argumentos del mandato.

Si el nombre de este script restart.sh así es como se lo llamaría:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &

Otros consejos

Me disculpo por la respuesta larga (por favor, vea los comentarios sobre la forma en que mi respuesta uñas la especificación). Estoy tratando de estar incompleta, por lo que tiene tan bueno de una pierna hacia arriba como sea posible. : -)

Si usted es capaz de instalar programas (tener acceso a la raíz), y está dispuesto a hacer trabajo de campo de una sola vez para establecer la secuencia de comandos para la ejecución del demonio (es decir, más complicado que simplemente especificando los argumentos de línea de comandos para ejecutar en el línea de comandos, pero sólo necesitan realizarse una vez por servicio), tengo una manera que sea más robusto.

Se trata de utilizar daemontools . El resto de la entrada se describe cómo configurar los servicios utilizando daemontools.

Configuración inicial

  1. Siga las instrucciones de Cómo instalar daemontools . Algunas distribuciones (por ejemplo, Debian, Ubuntu) ya tienen paquetes para ella, por lo que sólo tiene que utilizar.
  2. Crear un directorio llamado /service. El instalador ya debería haber hecho esto, pero simplemente verificar, o si la instalación manual. Si no te gusta este lugar, se puede cambiar en el script svscanboot, aunque la mayoría de los usuarios daemontools están acostumbrados a utilizar /service y se confundirán si no lo utiliza.
  3. Si estás usando Ubuntu u otra distribución que no utiliza init estándar (es decir, no utiliza /etc/inittab), tendrá que utilizar el inittab pre-instalado como base para la organización de svscanboot a ser llamado por init . No es difícil, pero hay que saber cómo configurar el init que utiliza su sistema operativo. svscanboot es un script que llama svscan, lo que hace el trabajo principal de buscar los servicios; se llama de manera init init arreglará para reiniciarlo si muere por cualquier razón.

configuración de cada servicio

  1. Cada servicio necesita un directorio de servicios , que almacena información sobre el servicio de limpieza. También se puede hacer un lugar para albergar a estos directorios de servicios para que estén en un solo lugar; normalmente utilizo /var/lib/svscan, pero cualquier nueva ubicación va a estar bien.
  2. Yo suelo usar un guión para configurar el directorio de servicios, para ahorrar una gran cantidad de trabajo manual repetitivo . por ejemplo.,

    sudo mkservice -d /var/lib/svscan/some-service-name -l -u user -L loguser "command line here"
    

    donde some-service-name es el nombre que desea dar a su servicio, user es que el usuario ejecute ese servicio, y loguser es que el usuario ejecute el registrador como. (El registro se explicó en tan sólo un poco.)

  3. El servicio tiene que ejecutar en el primer plano . Si su programa de fondos por defecto, pero tiene una opción para desactivar eso, y luego hacerlo. Si los fondos del programa sin una manera de desactivarlo, leer sobre fghack , aunque esto viene a una solución de compromiso:. ya no se puede controlar utilizando el programa svc
  4. Editar el guión run para asegurarse de que está haciendo lo que quiere. Es posible que deba realizar una llamada sleep en la parte superior, si espera que su servicio para salir con frecuencia.
  5. Cuando todo está correctamente configurado, cree un enlace simbólico en /service que apuntan a su directorio de servicios. (No ponga directorios de servicios directamente dentro /service;. Que hace que sea más difícil de quitar el servicio de reloj de svscan)

Inicio de sesión

  1. La forma daemontools de la tala es tener los mensajes de registro de servicio de escritura en la salida estándar (o error estándar, si está utilizando scripts generados con mkservice); svscan se encarga de enviar mensajes de registro al servicio de registro.
  2. El servicio de registro lleva los mensajes de registro desde la entrada estándar. El servicio de registro de la escritura b generadaY mkservice creará archivos de registro, con sellos de tiempo se gira automáticamente en el directorio log/main. El archivo de registro actual se llama current.
  3. El servicio de registro puede iniciarse y detenerse de forma independiente del servicio principal.
  4. Tubería los archivos de registro a través de tai64nlocal se traducirá las marcas de tiempo en un formato legible por humanos . (Tai64n es una marca de tiempo atómico de 64 bits con un recuento de nanosegundo.)

servicios de control

  1. svstat para obtener el estado de un servicio. Tenga en cuenta que el servicio de registro es independiente y tiene su propio estado.
  2. Usted controla su servicio (iniciar, detener, reiniciar, etc.) utilizando svc . Por ejemplo, para reiniciar el servicio, svc -t /service/some-service-name uso; -t significa "enviar SIGTERM".
  3. Otras señales disponibles incluyen -h (SIGHUP), -a (SIGALRM), -1 (SIGUSR1), -2 (SIGUSR2), y -k (SIGKILL).
  4. Para bajar el servicio, -d uso. También puede evitar que un servicio se inicie automáticamente en el arranque mediante la creación de un archivo llamado down en el directorio de servicios.
  5. Para iniciar el servicio, -u uso. Esto no es necesario a menos que se lo bebió con anterioridad (o configurar para que no se inicie automáticamente).
  6. Para solicitar el supervisor para salir, el uso -x; por lo general se utiliza con -d dar por terminado el servicio también. Esta es la forma habitual para permitir que un servicio sea retirado, pero hay que desvincular el servicio de /service primera, o de lo contrario svscan se reiniciará el supervisor. Además, si ha creado su servicio con un servicio de registro (mkservice -l), recuerde que debe salir también el supervisor de registro (por ejemplo, svc -dx /var/lib/svscan/some-service-name/log) antes de retirar el directorio de servicios.

Resumen

Pros:

  1. daemontools proporciona una manera a prueba de balas para crear y gestionar servicios. Yo lo uso para mis servidores, y lo recomiendo.
  2. Su sistema de registro es muy robusto, como es el centro de servicio de auto-arranque.
  3. Debido a que comienza con los servicios de un shell script que escriba / melodía, usted puede adaptar su servicio como usted quiera.
  4. Las potentes herramientas de control de servicios: puedes enviar la mayoría de cualquier señal a un servicio, y puede llevar los servicios arriba y hacia abajo de forma fiable
  5. .
  6. Sus servicios están garantizados un entorno de ejecución limpia: van a ejecutar con el mismo entorno, los límites del proceso, etc., lo que proporciona init
  7. .

Contras:

  1. Cada servicio requiere un poco de configuración. Afortunadamente, esto sólo hay que hacer una vez por servicio.
  2. Los servicios deben ser configuradas para ejecutarse en el primer plano. Además, para obtener mejores resultados, deben ser configurados para conectarse a la salida estándar / error estándar, en lugar de los archivos de registro del sistema o de otro tipo.
  3. curva de aprendizaje empinada si eres nuevo en el camino daemontools de hacer las cosas. Tendrá que reiniciar los servicios utilizando svc, y no se puede ejecutar las secuencias de comandos se ejecutan directamente (ya que entonces no estarían bajo el control del supervisor).
  4. Un montón de archivos de limpieza, y un montón de procesos de limpieza. Cada servicio tiene su propio directorio de servicios, y cada servicio utiliza un proceso de auto-supervisor para reiniciar el servicio si muere. (Si usted tiene muchos servicios, verá lotes de procesos supervise en su tabla de procesos.)

En el equilibrio, creo daemontools un excelente sistema para sus necesidades. Doy la bienvenida a cualquier pregunta acerca de cómo configurarlo y mantenerlo.

Usted debe echar un vistazo a daemonize . Permite detectar segunda copia (pero utiliza el 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 usted necesita para crear apropiada init-script.

Puede utilizar la siguiente plantilla:

#!/bin/sh
#
# mydaemon     This shell script takes care of starting and stopping
#               the <mydaemon>
#

# Source function library
. /etc/rc.d/init.d/functions


# Do preliminary checks here, if any
#### START of preliminary checks #########


##### END of preliminary checks #######


# Handle manual control parameters like start, stop, status, restart, etc.

case "$1" in
  start)
    # Start daemons.

    echo -n $"Starting <mydaemon> daemon: "
    echo
    daemon <mydaemon>
    echo
    ;;

  stop)
    # Stop daemons.
    echo -n $"Shutting down <mydaemon>: "
    killproc <mydaemon>
    echo

    # Do clean-up works here like removing pid files from /var/run, etc.
    ;;
  status)
    status <mydaemon>

    ;;
  restart)
    $0 stop
    $0 start
    ;;

  *)
    echo $"Usage: $0 {start|stop|status|restart}"
    exit 1
esac

exit 0

Creo que es posible que desee probar start-stop-daemon(8) . Echa un vistazo a los scripts en /etc/init.d en cualquier distribución de Linux para los ejemplos. Se puede encontrar procesos iniciados por línea de comandos invocado o archivo PID, para que coincida con todos sus requisitos excepto ser un organismo de control para su guión. Pero siempre se puede empezar otra secuencia de comandos de vigilancia demonio que simplemente se reinicia la secuencia de comandos si es necesario.

Como alternativa a la daemonize y daemontools ya se ha mencionado, no es el demonio de href="http://libslack.org/daemon/" rel="noreferrer"> comando del paquete libslack.

daemon es bastante configurable y se preocupa por todas las cosas demonio tedioso como el reinicio automático, el registro o manipulación pidfile.

Si está utilizando OS X en concreto, le sugiero que tome un vistazo a cómo funciona la launchd. Se comprobará automáticamente para asegurar su script se está ejecutando y relanzar si es necesario. También incluye todo tipo de funciones de programación, etc. Se debe satisfacer tanto el requisito 1 y 2.

En cuanto a asegurar sólo una copia de la secuencia de comandos se puede ejecutar, es necesario utilizar un archivo PID. Generalmente escribo un archivo a /var/run/.pid que contiene un PID de la instancia de ejecución actual. si existe el archivo cuando el programa se ejecuta, comprueba si el PID en el archivo se encuentra en ejecución (el programa puede haber olvidado estropeado o eliminar el archivo PID de otra manera). Si es así, abortar. Si no es así, empezar a correr y sobreescribir el archivo PID.

daemontools ( http://cr.yp.to/daemontools.html ) es una conjunto de utilidades bastante empedernidos que se utilizan para hacer esto, escrito por Bernstein dj. He utilizado este con cierto éxito. La parte molesta de esto es que ninguno de los scripts devuelve ningún resultado visible cuando se ejecutan - sólo los códigos de retorno invisibles. Pero una vez que se está ejecutando es a prueba de balas.

En primer lugar obtener createDaemon() de http://code.activestate.com/recipes/278731/

A continuación, el código principal:

import subprocess
import sys
import time

createDaemon()

while True:
    subprocess.call(" ".join(sys.argv[1:]),shell=True)
    time.sleep(10)

Esta es una versión de trabajo completa con un ejemplo que se puede copiar en un directorio vacío y probar (después de instalar las dependencias de CPAN, que son Getopt :: largo , archivo :: Spec , archivo :: Pid , y IPC :: System :: simple - todo bastante estándar y son muy recomendables para cualquier hacker:. puede instalar todos a la vez con cpan <modulename> <modulename> ...)


keepAlive.pl:

#!/usr/bin/perl

# Usage:
# 1. put this in your crontab, to run every minute:
#     keepAlive.pl --pidfile=<pidfile> --command=<executable> <arguments>
# 2. put this code somewhere near the beginning of your script,
#    where $pidfile is the same value as used in the cron job above:
#     use File::Pid;
#     File::Pid->new({file => $pidfile})->write;

# if you want to stop your program from restarting, you must first disable the
# cron job, then manually stop your script. There is no need to clean up the
# pidfile; it will be cleaned up automatically when you next call
# keepAlive.pl.

use strict;
use warnings;

use Getopt::Long;
use File::Spec;
use File::Pid;
use IPC::System::Simple qw(system);

my ($pid_file, $command);
GetOptions("pidfile=s"   => \$pid_file,
           "command=s"   => \$command)
    or print "Usage: $0 --pidfile=<pidfile> --command=<executable> <arguments>\n", exit;

my @arguments = @ARGV;

# check if process is still running
my $pid_obj = File::Pid->new({file => $pid_file});

if ($pid_obj->running())
{
    # process is still running; nothing to do!
    exit 0;
}

# no? restart it
print "Pid " . $pid_obj->pid . " no longer running; restarting $command @arguments\n";

system($command, @arguments);

example.pl:

#!/usr/bin/perl

use strict;
use warnings;

use File::Pid;
File::Pid->new({file => "pidfile"})->write;

print "$0 got arguments: @ARGV\n";

Ahora se puede invocar el ejemplo anterior con: ./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3 y la pidfile archivo será creado, y verá la salida:

Pid <random number here> no longer running; restarting ./example.pl 1 2 3
./example.pl got arguments: 1 2 3

También puede intentar Monit . Monit es un servicio que supervisa e informa sobre otros servicios. Mientras que se utiliza principalmente como una forma de notificar (por correo electrónico y SMS) sobre los problemas de tiempo de ejecución, sino que también puede hacer lo que la mayoría de las otras sugerencias aquí han abogado. Se puede auto (re) iniciar y detener programas, enviar mensajes de correo electrónico, iniciar otras secuencias de comandos, y mantener un registro de salida que se puede recoger. Además, he encontrado que es fácil de instalar y mantener ya que no hay documentación sólida.

Usted podría dar una oportunidad a inmortal Es un * nix multiplataforma (OS agnóstico) supervisor.

En un intento rápida en MacOS:

brew install immortal

En el caso de utilizar FreeBSD de los puertos o mediante el uso de PKG:

pkg install immortal

En Linux mediante la descarga de los archivos binarios precompilados o de la fuente: https://immortal.run/source/

Usted puede utilizar de esta manera:

immortal -l /var/log/date.log date

O por un archivo de configuración YAML que le da más opciones, por ejemplo:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

Si desea mantener también la salida de error estándar en un archivo separado que podría utilizar algo como:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
stderr:
    file: /var/log/date-error.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

he hecho una serie de mejoras en la otra respuesta .

  1. la salida estándar de este guión es puramente compone de salida estándar que viene de su hijo a menos que salga debido a la detección de que el comando que ya se está ejecutando
  2. limpia después de su pidfile cuando terminado
  3. período de tiempo de espera configurable opcional (acepta cualquier argumento numérico positivo, envía a sleep)
  4. pronta Uso en -h
  5. ejecución de comandos arbitrarios, en lugar de la ejecución del comando único. La última Arg o argumentos restantes (si hay más de una última arg) son enviados a eval, para que pueda construir cualquier tipo de secuencia de comandos shell como una cadena para enviar a este script como último arg (o argumentos de cola) para que daemonize
  6. comparaciones recuento argumento hecho con -lt en lugar de <

Aquí está la secuencia de comandos:

#!/bin/sh

# this script builds a mini-daemon, which isn't a real daemon because it
# should die when the owning terminal dies, but what makes it useful is
# that it will restart the command given to it when it completes, with a
# configurable timeout period elapsing before doing so.

if [ "$1" = '-h' ]; then
    echo "timeout defaults to 1 sec.\nUsage: $(basename "$0") sentinel-pidfile [timeout] command [command arg [more command args...]]"
    exit
fi

if [ $# -lt 2 ]; then
    echo "No command given."
    exit
fi

PIDFILE=$1
shift

TIMEOUT=1
if [[ $1 =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
        TIMEOUT=$1
        [ $# -lt 2 ] && echo "No command given (timeout was given)." && exit
        shift
fi

echo "Checking pid in file ${PIDFILE}." >&2

#Check to see if process running.
if [ -f "$PIDFILE" ]; then
    PID=$(< $PIDFILE)
    if [ $? = 0 ]; then
        ps -p $PID >/dev/null 2>&1
        if [ $? = 0 ]; then
            echo "This script is (probably) already running as PID ${PID}."
            exit
        fi
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

cleanup() {
        rm $PIDFILE
}
trap cleanup EXIT

# Run command until we're killed.
while true; do
    eval "$@"
    echo "I am $$ and my child has exited; restart in ${TIMEOUT}s" >&2
    sleep $TIMEOUT
done

Uso:

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/'
Checking pid in file pidfilefortesting.
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
^C

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/' 2>/dev/null
azzzcd
azzzcd
azzzcd
^C

Tenga en cuenta que si ejecuta este script desde diferentes directorios se pueden utilizar diferentes pidfiles y no detecta ningún instancias en ejecución existentes. Puesto que está diseñado para funcionar y reiniciar comandos efímeras proporcionados a través de un argumento que no hay manera de saber si algo ha sido ya iniciado, porque ¿quién puede decir si se trata de el mismo comando o no? Para mejorar esta aplicación de únicamente con una sola instancia de algo, una solución específica a la situación que se requiere.

Además, para que funcione como un demonio adecuada, debe utilizar (en el mínimo) nohup como la otra respuesta menciona. No he hecho ningún esfuerzo para proporcionar cualquier capacidad de resistencia a las señales del proceso puede recibir.

Un punto a tener en cuenta es que la muerte de este script (si se llama desde otro script que se mata, o con una señal) puede no tener éxito en matar al niño, especialmente si el niño es más aún otra guión. No estoy seguro de por qué esto es, pero parece ser algo relacionado con las obras eval manera, que es un misterio para mí. Por lo tanto, puede ser prudente para reemplazar esa línea con algo que sólo acepta un único comando como en la otra respuesta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top