Kann startd Programme häufiger als alle 10 Sekunden ausführen?

8

Ich habe einige Dienste wie diesen, die ich fast sofort ausführen möchte, nachdem Dateien geändert wurden.

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

Selbst wenn ThrottleInterval auf 1 oder 0 gesetzt wurde, werden sie höchstens alle 10 Sekunden ausgeführt.

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 sagt nur, dass Programme standardmäßig nicht mehr als alle 10 Sekunden ausgeführt werden, erwähnt aber nicht, dass ThrottleInterval nicht darunter eingestellt werden konnte.

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.

Sie können das Programm oder Skript 10 Sekunden lang laufen lassen und jede Sekunde auf Änderungen achten:

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

Oder dasselbe 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

Aber gibt es eine Möglichkeit, das Zeitlimit zu umgehen oder zu verkürzen? Dies gilt auch für Ordneraktionen.

Lri
quelle

Antworten:

9

Es gibt keine Möglichkeit, das Zeitlimit zu umgehen oder zu verkürzen.

In der Apple-Dokumentation zum Erstellen von gestarteten Jobs heißt es:

Wichtig Wenn Ihr Daemon nach dem Start zu schnell heruntergefahren wird, glaubt launchd möglicherweise, dass er abgestürzt ist. Daemons, die dieses Verhalten fortsetzen, werden möglicherweise angehalten und nicht erneut gestartet, wenn zukünftige Anforderungen eintreffen. Um dieses Verhalten zu vermeiden, fahren Sie nach dem Start mindestens 10 Sekunden lang nicht herunter.

Ihr Programm oder Skript muss mindestens 10 Sekunden lang ausgeführt werden. Erwägen Sie die Implementierung einer Schleife, um in den letzten zehn Sekunden nach Datumsänderungsdaten zu suchen, zehn Sekunden lang zu schlafen und zu wiederholen.

Alternativ können Sie bestimmte Dateien mithilfe der kqueue- oder FSEvents-APIs anzeigen. Diese Frage Stackoverflow kann hilfreich sein, auf Dateiebene Dateisystem - Änderungsbenachrichtigung in Mac OS X .

Graham Miln
quelle
2

Sie können Ihr Skript in einer Schleife laufen lassen, um nach geänderten Dateien zu suchen, anstatt es zu beenden, wenn es fertig ist. Lassen Sie es einige Sekunden lang schlafen, nachdem Sie nach den geänderten Dateien gesucht haben. Wenn geänderte Dateien gefunden werden, fahren Sie mit dem Skript fort. Wenn nicht, schlafen Sie wieder.

Lassen Sie dann Ihr Skript alle x Minuten starten, falls der vorherige Lauf ausfällt. Codieren Sie den Anfang Ihres Skripts, um zu überprüfen, ob bereits eine andere Instanz ausgeführt wird, und beenden Sie sich in diesem Fall.

Insomniac Software
quelle
launchd scheint keine andere Instanz zu starten, wenn die vorherige noch ausgeführt wird.
Lri
launchd startet nicht mehrere Instanzen desselben Jobtickets.
Graham Miln
1

Wenn Sie ein Skript öfter als alle 10 Sekunden starten müssen, kann es im Hinblick auf "Forking" teuer sein (lesen Sie: Zuweisen von Speicher, Starten neuer Prozesse usw.).

Daher ist es in diesem Fall am besten, einen eigenen " Daemon " zu schreiben (Programm, was im Hintergrund läuft)

Ich empfehle Ihnen, eine "leistungsfähigere" Sprache als BASH zu verwenden (mein Favorit ist "Perl", aber Ruby ist auch in Ordnung), da ein guter Daemon Timeouts, Alarme usw. verarbeitet - Dinge, die in Pure Bash zu schwer zu implementieren sind. (Natürlich kann der Daemon auch Ihre Bash-Skripte ausführen - falls erforderlich). Die Grundlagen sind:

  • Skript, was endlos läuft und auf ein Ereignis wartet. Das Ereignis kann eine Netzwerkeingabe oder ein einfacher Timer oder ähnliches sein. Wenn das Ereignis eintrifft (z. B. der Wartezustand beendet ist), macht das Skript, was Sie wollen, und der Zyklus wird wiederholt.

In der Perl-Welt gibt es bereits Module, die Ihr Skript als "Daemon" -Prozess optimieren, zum Beispiel Proc :: Daemon . Ich habe keine Erfahrung mit Rubin, aber dieser Artikel kann Ihnen helfen.

Sie können Ihren Daemon-Prozess über Launchd beim Systemstart oder über die Automator-App beim Anmelden oder manuell über das Terminal starten.

jm666
quelle