5 votos

¿Por qué un Script de Shell Reventado SIGTERM de Trabajo Cuando se Ejecuta Manualmente, Pero No Cuando se Ejecuta a través de launchd?

Bueno, simplemente tengo un script de shell que debe esperar a que algo suceda, pero tiene un bloqueo de archivo y algunos procesos hijo que me necesita para asegurarse de que se arreglada si la secuencia de comandos se interrumpe.

He conseguido sin problema mediante el uso de la trap comando para establecer algunas acciones apropiadas, y hemos venido para arriba con un guión que parece un poco a esto:

#!/bin/sh
LOG="$0.log"

# Create a lock-file to prevent simultaneous access
lockfile -l 86400 "$LOG.lock" || $(echo 'Locking failed' >&2 && exit 3)

# Create trap for interrupt and cleanup
on_complete() {
    echo $(date +%R)' Ended.' >> "$LOG"
    kill $(jobs -p)
    rm -f "$LOG.lock"
    exit
}
trap 'on_complete 2> /dev/null' SIGTERM SIGINT SIGHUP EXIT

# Do nothing
echo $(date +%R)' Running…' >> "$LOG"
sleep 86400 &
while wait; do sleep 86400 &; done

Esto se puede ejecutar bien en un terminal a través de la sh Example.sh, y terminando con Ctrl + C, haciendo que se retire su bloqueo de archivo sin ningún tipo de alboroto.

Luego traté de crear un launchd de empleo para esta secuencia de comandos así:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.example</string>
    <key>ProgramArguments</key>
    <array>
        <string>sh</string>
        <string>~/Downloads/Example.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>EnableGlobbing</key>
    <true/>
</dict>
</plist>

La creación de Example.sh y el Ejemplo.plist de la anterior, en la ~/Downloads carpeta me permite ejecutar el launchd de empleo a través de la launchd load ~/Downloads/Example.plist y al final de ella a través de la launchd unload ~/Downloads/Example.plist. Sin embargo, finalizando el trabajo no causa SIGTERM para llegar a la secuencia de comandos, que es el lugar SIGKILL'd después de los 20 segundos de tiempo de espera.

Lo que me gustaría saber es, ¿por qué no es mi script recibiendo SIGTERM, y ¿cómo puedo asegurarme de que hace?

6voto

aye Puntos 36

El último problema aquí es que Bash no suele matar a su no-builtin los niños.

If bash is waiting for a command to complete and receives a signal for which a
trap has been set, the trap will not be executed until the command completes.
When bash is waiting for an asynchronous command  via  the  wait  builtin, the
reception of a signal for which a trap has been set will cause the wait builtin
to return immediately with an exit status greater than 128, immediately after
which  the trap is executed.

Cuando usted golpea <CTRL>+<C> estás matando la secuencia de comandos de shell, el cual se comporta normalmente, pero el sueño sigue vivo. Uso ps a ver.

Cuando se trate de detener las cosas externamente, a través de la kill, luego de Bash como el anterior. Después de algún período de tiempo (supongo que por 20 segundos) launchd , a continuación, emite un kill -9 que el script no se puede interceptar.

La solución es cuestión de esperar después de que el sueño, para indicar a Bash que puede interrumpir el mismo:

sleep 86400 & wait

Esto permitirá que la secuencia de comandos para ser interrumpido, pero el sueño aún sobrevivir. Estoy seguro de que hay una manera de matar a los niños, pero no me molesta mirando hacia arriba...

4voto

ant Puntos 31

Al darse cuenta de que usted ha compartido con nosotros una esencialmente un fragmento de código y no está claro qué más eres el demonio está buscando la forma de lograr otro que el de realizar alguna acción cada tantos segundos. Por lo tanto, voy a hacer algunos supuestos, sólo se basa en lo que has escrito.

  1. Parece que te estás usando el archivo de bloqueo para evitar la duplicación de lanzamiento.
  2. Parece que necesita la trampa para limpiar el archivo de bloqueo se utiliza para implementar la prueba para asegurar la singularidad.
  3. Además parece que su demonio es hacer un sueño bucle para despertar periódicamente y realizar alguna acción. (Sólo dormir más, en el ejemplo).

Todas estas son cuestiones que launchd está destinado a resolver de mejor manera en virtud de Darwin (y por lo tanto OS X).

En cuanto a la pregunta(s) con la descarga y SIGTERM, específicamente, cuando unload de su launchdeamon se envía una señal SIGKILL en lugar de un SIGTERM. Si usted sólo quería detener el trabajo o enviar un SIGTERM a continuación, utilice stop en lugar de unload.

Si quieres un SIGTERM enviado en unload puede que sea necesario establecer EnableTransactions. Del mismo modo, si usted tiene tareas de limpieza y desea que el demonio a las señales recibidas para la limpieza y SIGTERM, a continuación, debe establecer EnableTransactions como parte de la launchd plist para la secuencia de comandos. <key>EnableTransactions</key><true/>. Esto se describe en la documentación en https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html

Pero los tres mecanismos mencionados son innecesarios dado launchd...

En virtud de Darwin / OS X utilizando launchdaemons el método apropiado para la implementación de un sueño bucle demonio es el uso de StartInterval a ejecutar en un intervalo de o StartCalendarInterval a ejecutar en base a horas específicas. El uso de StartCalendarInterval además le da la ventaja de que cuando el sistema está en reposo, que se ejecutará una pasada intervalo de tiempo en lugar de tener que esperar para el siguiente intervalo, y en general es lo que usted desea en estas situaciones. Si usted tiene un trabajo que solo quieren estar invoca, también considere el uso de KeepAlive como parte de la plist.

Por lo que parece, desde el código de ejemplo que usted ha proporcionado -- usted sólo desea ejecutar algo que todos los 86400 segundos. Si este es el caso, entonces launchd tiene un mecanismo para hacer esto que usted debe estar utilizando en su lugar y evita la necesidad de su archivo de bloqueo de trampa y que en conjunto launchd está diseñado para manejar todo esto para usted automáticamente. Ese mecanismo es StartInterval y cuando se define lanzará su demonio cada N segundos. Launchd también se asegura de que no ha lanzado varias copias de su demonio.

Este mecanismo se describe en el launchd docs en https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html donde dice:

StartInterval <integer>
This optional key causes the job to be started every N seconds.  If the system is
asleep, the job will be started the next time the computer wakes up.  If multiple
intervals transpire before the computer is woken, those events will be coalesced 
into one event upon wake from sleep.

Lo de Darwin-ized script ~/Downloads/Example.sh sería algo muy simplemente que ahora como esta:

#!/bin/sh
echo $(date +%R)' Running…' # or whatever it is you wanted to do on the interval

Y su plist sería algo como esto:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.example</string>
    <key>ProgramArguments</key>
    <array>
        <string>sh</string>
        <string>~/Downloads/Example.sh</string>
    </array>
    <key>EnableGlobbing</key>
    <true/>
    <key>StartInterval</key>
    <integer>86400</integer>
    <key>StandardOutPath</key>
    <string>/mypathtolog/myjob.log</string>
    <key>StandardErrorPath</key>
    <string>/mypathtolog/myjob.log</string>
</dict>
</plist>

Nota también he ajustado a esta opción para establecer el registro de archivos, aquí en una de Darwin/launchd igual manera, en lugar de en el propio script. (Usted podría, por supuesto, eliminarlos y controlar en su guión, pero no es necesario dado launchd.)

Me gustaría señalar que también se podría implementar esto usando Program como así:

<key>Program</key>
<string>sh</string>
<key>ProgramArguments</key>
<array>
    <string>~/Downloads/Example.sh</string>
</array>

Usted también puede encontrar http://launchd.info una referencia útil también junto con la Manzana docs para cómo launchd opera en https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/Introduction.html

La información acerca de los demonios que se ejecute periódicamente se puede encontrar en https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/ScheduledJobs.html#//apple_ref/doc/uid/10000172i-CH1-SW2

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X