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

8

Tengo algunos servicios como este que me gustaría ejecutar casi inmediatamente después de modificar 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 configuró en 1 o 0, solo se ejecutan cada 10 segundos como máximo.

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 solo dice que los programas no se ejecutan más de cada 10 segundos de forma predeterminada, pero no menciona que ThrottleInterval no se pudo establecer 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.

Puede mantener el programa o el 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 manera de evitar o disminuir el límite de tiempo? También se aplica a las acciones de carpeta.

Lri
fuente

Respuestas:

9

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

Documentación de Apple sobre Creación de trabajos de Launchd establece lo siguiente:

Importante Si su demonio se apaga demasiado rápido después de ser lanzado, launchd puede pensar que se ha estrellado. Demonios que continúan esto.   El comportamiento puede suspenderse y no volver a iniciarse cuando futuras solicitudes   llegar. Para evitar este comportamiento, no apague por lo menos 10   Segundos después del lanzamiento.

Su programa o script debe seguir funcionando durante al menos 10 segundos. Considere implementar un bucle para verificar las fechas de modificación de los archivos en los últimos diez segundos, dormir diez segundos y repetir.

Alternativamente, puede ver archivos específicos usando el kqueue o FSEvents APIs. Esta pregunta de StackOverflow puede ser útil, Notificación de cambio de sistema de archivos a nivel de archivo en Mac OS X .

Graham Miln
fuente
2

Podría mantener su secuencia de comandos ejecutándose en un bucle buscando archivos modificados en lugar de salir cuando se termine. Hágalo dormir por unos segundos después de verificar los archivos modificados. Si encuentra archivos modificados, continúe con el script. Si no, duerme de nuevo.

Luego, haga que launchd inicie su script cada x minutos en caso de que la ejecución anterior muera. Codifique el principio de su secuencia de comandos para verificar si otra instancia ya se está ejecutando y, de ser así, salga de sí mismo.

Insomniac Software
fuente
launchd no parece iniciar otra instancia si la anterior todavía se está ejecutando.
Lri
launchd no iniciará varias instancias del mismo ticket de trabajo.
Graham Miln
1

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

Por lo tanto, en este caso es el mejor para escribir el tuyo propio ". demonio "(programa, lo que se ejecuta en segundo plano)

Te recomiendo que uses un lenguaje "más capaz" como 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, lo que es demasiado difícil de implementar en bash puro. (Por supuesto, el demonio también puede ejecutar sus scripts de bash, si es necesario). Los fundamentos son:

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

En el mundo Perl ya existen módulos que optimizan su script como proceso "daemon", por ejemplo. Proc :: Daemon . No tengo experiencia con el rubí, pero Este artículo puedo ayudarte.

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

jm666
fuente