Launchd può eseguire programmi più frequentemente di ogni 10 secondi?


8

Ho alcuni servizi come questo che vorrei eseguire quasi immediatamente 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 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 ogni 10 secondi per impostazione predefinita, ma non menziona che ThrottleInterval non può essere impostato al di sotto di quello.

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 delle cartelle.

Risposte:


9

Non è possibile ignorare o ridurre il limite di tempo.

La documentazione di Apple relativa alla creazione di lavori Launchd afferma quanto segue:

Importante Se il tuo demone si spegne troppo velocemente dopo essere stato lanciato, launchd potrebbe pensare che si sia arrestato in modo anomalo. I demoni che continuano questo comportamento possono essere sospesi e non lanciati di nuovo quando arrivano richieste future. Per evitare questo comportamento, non chiudere per almeno 10 secondi dopo l'avvio.

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

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


2

È possibile mantenere lo script in esecuzione in un ciclo verificando la presenza di file modificati anziché chiuderlo al termine. Fallo dormire per alcuni secondi dopo aver verificato i file modificati. Se trova file modificati, continua con lo script. In caso contrario, dormire di nuovo.

Quindi avviare launchd ogni script ogni x minuti nel caso in cui la precedente esecuzione scompaia. Codificare l'inizio dello script per verificare se è già in esecuzione un'altra istanza e, in tal caso, uscire da sé.


launchd non sembra avviare un'altra istanza se la precedente è ancora in esecuzione.
Lri,

launchd non avvierà più istanze dello stesso job ticket.
Graham Miln,

1

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

Pertanto, in questo caso è il migliore per scrivere il proprio " demone " (programma, ciò che viene eseguito in background)

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

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

Nel mondo perl esistono già moduli che trasformano il tuo script come processo "daemon", ad esempio Proc :: Daemon . Non ho esperienza con il rubino, ma questo articolo può aiutarti.

È possibile avviare il processo daemon tramite Launchd all'avvio del sistema o dall'app Automator al momento dell'accesso o dal Terminale manualmente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.