Può lanciare programmi eseguiti più frequentemente di ogni 10 secondi?

8

Ho alcuni servizi come questo che mi piacerebbe eseguire quasi subito dopo la modifica dei file.

<?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>

Anche se ThrottleInterval era impostato su 1 o 0, vengono eseguiti solo al massimo ogni 10 secondi.

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 dice solo che i programmi non vengono eseguiti più di 10 secondi per impostazione predefinita, ma non menzionano che ThrottleInterval non può essere impostato al di sotto di questo.

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.

È possibile mantenere il programma o lo script in esecuzione per 10 secondi e osservare le modifiche ogni secondo:

#!/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 stesso in 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

Ma c'è un modo per aggirare o ridurre il limite di tempo? Si applica anche alle azioni della cartella.

    
posta user495470 09.09.2012 - 16:23
fonte

3 risposte

9

Non c'è modo di ignorare o ridurre il limite di tempo.

La documentazione di Apple riguardante Creazione di Launchd Jobs afferma seguenti:

Important If your daemon shuts down too quickly after being launched, launchd may think it has crashed. Daemons that continue this behavior may be suspended and not launched again when future requests arrive. To avoid this behavior, do not shut down for at least 10 seconds after launch.

Il tuo programma o script deve continuare a funzionare per almeno 10 secondi. Prendi in considerazione l'implementazione di un ciclo per verificare le date di modifica dei file negli ultimi dieci secondi, dormendo per dieci secondi e ripetendo.

In alternativa, puoi guardare file specifici usando kqueue o FSEvents API. Questa domanda di StackOverflow può essere utile, Notifica di modifica del filesystem a livello di file in Mac OS X .

    
risposta data 11.09.2012 - 12:38
fonte
2

È possibile mantenere lo script in esecuzione in un ciclo per la ricerca di file modificati invece di uscire quando è finito. Lascia dormire per alcuni secondi dopo aver controllato i file modificati. Se trova file modificati, continua con lo script. Altrimenti, dormi di nuovo.

Quindi avviare launchd lo script ogni x minuti solo nel caso in cui l'esecuzione precedente muoia. Codifica l'inizio dello script per verificare se un'altra istanza è già in esecuzione e, in tal caso, uscire da se stessa.

    
risposta data 11.09.2012 - 10:17
fonte
1

Se è necessario avviare uno script più spesso di ogni 10 secondi, può essere costoso in termini di "forking" (leggi: allocazione della memoria, avvio di nuovi processi, ecc.)

Pertanto, in questo caso è meglio scrivere il proprio " daemon " (programma, che viene eseguito in background)

Ti consiglio di usare una lingua "più capace" come BASH (il mio preferito è "perl", ma anche ruby è OK) perché un buon demone gestisce timeout, allarmi e così via - cose che sono troppo difficili da implementare in puro bash . (Naturalmente, il demone può eseguire anche gli script di bash, se necessario). Le basi sono:

  • script ciò che è in esecuzione senza fine e in attesa di qualche evento. L'evento può essere un input di rete, un timer semplice o qualcosa del genere. Quando arriva l'evento (ad es. Lo stato di attesa terminato) lo script farà ciò che vuoi e il ciclo si ripete.

Nel mondo perl esiste già un modulo che sintonizza il tuo script come processo "daemon", ad esempio Proc :: Daemon . Non ho esperienza con ruby, ma questo articolo può aiutarti.

È possibile avviare il processo demone tramite Launchd all'avvio del sistema o dall'app di automatore quando si effettua l'accesso o dal terminale manualmente.

    
risposta data 11.09.2012 - 19:57
fonte

Leggi altre domande sui tag