10 votos

¿Puede launchd ejecutar programas con más frecuencia que cada 10 segundos?

Tengo algunos servicios de este tipo que me gustaría ejecutar casi inmediatamente después de que se modifiquen los archivos.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>     
        <string>say</string>
        <string>a</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/username/Desktop/</string>
    </array>
</dict>
</plist>

Incluso si ThrottleInterval se estableció en 1 o 0, sólo se ejecutan como máximo cada 10 segundos.

9/9/12 4:57:05.457 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 7 seconds
9/9/12 4:57:09.541 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 3 seconds

man launchd.plist sólo dice que los programas no se ejecutan más que cada 10 segundos por defecto, pero no menciona que ThrottleInterval no puede ser fijado por debajo de eso.

ThrottleInterval <integer>
This key lets one override the default throttling policy imposed on jobs by launchd.
The value is in seconds, and by default, jobs will not be spawned more than once
every 10 seconds.  The principle behind this is that jobs should linger around just
in case they are needed again in the near future. This not only reduces the latency
of responses, but it encourages developers to amortize the cost of program invoca-
tion.

Podrías mantener el programa o script en ejecución durante 10 segundos y observar los cambios cada segundo:

#!/bin/bash

start=$(date +%s)
prev=

until (( $(date +%s) >= $start + 10 )); do
    new=$(stat -f %m ~/Desktop/)
    [[ $prev != $new ]] && say a
    prev=$new
    sleep 1
done

O lo mismo en Ruby:

#!/usr/bin/env ruby

start = Time.now
prev = nil

until Time.now >= start + 10
  current = File.mtime("#{ENV['HOME']}/Desktop/")
  `say a` if current != prev
  prev = current
  sleep 1
end

Pero, ¿hay alguna forma de evitar o disminuir el límite de tiempo? También se aplica a las acciones de las carpetas.

10voto

Steve Evans Puntos 155

No hay manera de evitar o disminuir el límite de tiempo.

La documentación de Apple sobre Creación de puestos de trabajo en Launchd afirma lo siguiente:

Importante Si su demonio se apaga demasiado rápido después de ser lanzado, launchd puede pensar que se ha estrellado. Los dæmones que continúen con este comportamiento comportamiento pueden ser suspendidos y no lanzados de nuevo cuando lleguen futuras peticiones cuando lleguen futuras solicitudes. Para evitar este comportamiento, no se apague durante al menos 10 segundos después del lanzamiento.

Tu programa o script tiene que seguir funcionando durante al menos 10 segundos. Considere la posibilidad de implementar un bucle para comprobar las fechas de modificación de los archivos en los últimos diez segundos, durmiendo durante diez segundos, y repitiendo.

Alternativamente, puede ver archivos específicos utilizando la función kqueue o FSEvents APIs. Esta pregunta de StackOverflow puede ser útil, Notificación de cambios en el sistema de archivos a nivel de fichero en Mac OS X .

2voto

Lockie Puntos 636

Podrías mantener tu script ejecutado en un bucle comprobando los archivos modificados en lugar de salir cuando haya terminado. Haz que duerma durante unos segundos después de buscar los archivos modificados. Si encuentra archivos modificados, continúa con el script. Si no, duerme de nuevo.

Entonces haz que launchd inicie tu script cada x minutos por si acaso la ejecución anterior muere. Codifica el comienzo de tu script para comprobar si otra instancia ya se está ejecutando y, si es así, que se cierre.

1voto

jm666 Puntos 4489

Si necesita iniciar un script con más frecuencia que cada 10 segundos, puede ser costoso en términos de "bifurcación" (léase: asignación de memoria, inicio de nuevos procesos, etc.).

Por lo tanto, en este caso lo mejor es escribir su propio " daemon " (programa, lo que se ejecuta en segundo plano)

Te recomiendo que utilices un lenguaje "más capaz" que BASH (mi favorito es "perl", pero ruby también está bien) porque un buen demonio maneja los tiempos de espera, las alarmas y demás - cosas que son demasiado difíciles de implementar en bash puro. (Por supuesto, el demonio puede ejecutar su bash scripts también - si es necesario). Lo básico es:

  • scriptque se está ejecutando sin fin y esperando algún evento. El evento puede ser alguna entrada de red, o un simple temporizador o algo parecido. Cuando el evento llega (por ejemplo, el estado de espera terminó) el script hará lo que quiere y el ciclo se repite.

En el mundo perl ya existen módulos que sintonizan tu script como proceso "daemon", por ejemplo Proc::Daemon . No tengo experiencia con rubí, pero este artículo puede ayudarte.

Puede iniciar su proceso daemon a través de Launchd en el inicio del sistema, o desde la aplicación de automatización al iniciar la sesión, o desde la Terminal manualmente.

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