launchdは10秒ごとよりも頻繁にプログラムを実行できますか?


8

ファイルが変更された直後に実行したいこのようないくつかのサービスがあります。

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

ThrottleIntervalが1または0に設定されている場合でも、最大で10秒ごとにのみ実行されます。

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 デフォルトでは、プログラムは10秒を超えて実行されないというだけですが、ThrottleIntervalをそれ以下に設定できないことについては触れていません。

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.

プログラムまたはスクリプトを10秒間実行し続け、毎秒変更を監視できます。

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

または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

しかし、制限時間を回避または短縮する方法はありますか?また、フォルダアクションにも適用されます。

回答:


9

時間制限を回避または短縮する方法はありません。

起動ジョブの作成に関するAppleのドキュメントには、次のように記載されています。

重要起動後にデーモンがすぐにシャットダウンする場合、launchdはデーモンがクラッシュしたと考えることがあります。この動作を続けるデーモンは一時停止され、将来の要求が到着したときに再び起動されない場合があります。この動作を回避するには、起動後少なくとも10秒間はシャットダウンしないでください。

プログラムまたはスクリプトは、少なくとも10秒間実行し続ける必要があります。最後の10秒間のファイル変更日付をチェックし、10秒間スリープしてから繰り返すループを実装することを検討してください。

または、kqueueまたはFSEvents API を使用して特定のファイルを監視できます。このStackOverflowの質問は役立つかもしれません。MacOS Xでのファイルレベルのファイルシステム変更通知です。


2

スクリプトが実行されたときに終了する代わりに、変更されたファイルをチェックするループでスクリプトを実行し続けることができます。変更されたファイルを確認した後、数秒間スリープさせます。変更されたファイルが見つかった場合は、スクリプトを続行します。そうでない場合は、再び寝ます。

次に、前回の実行が停止した場合に備えて、x分ごとにスクリプトを起動します。スクリプトの先頭をコーディングして、別のインスタンスがすでに実行されているかどうかを確認し、実行されている場合は終了します。


以前のインスタンスがまだ実行されている場合、launchdは別のインスタンスを起動しないようです。
Lri

launchdは、同じジョブチケットの複数のインスタンスを起動しません。
Graham Miln

1

10秒ごとよりも頻繁にスクリプトを開始する必要がある場合は、「フォーク」という点でコストがかかる可能性があります(読み取り:メモリの割り当て、新しいプロセスの開始など)。

したがって、この場合は、独自の「デーモン」(プログラム、バックグラウンドで実行されるもの)を作成するのが最適です。

優れたデーモンがタイムアウトやアラームなどを処理するため、BASHとして「より有能な」言語を使用することをお勧めします(私のお気に入りは「perl」ですが、rubyもOKです)。(もちろん、デーモンは必要に応じてbashスクリプトも実行できます)。基本は次のとおりです。

  • 何が無限に実行され、何らかのイベントを待っているかをスクリプト化します。イベントには、ネットワーク入力、単純なタイマーなどがあります。イベントが到着すると(待機状態が終了した場合など)、スクリプトは必要な処理を実行し、サイクルが繰り返されます。

Perlの世界には、スクリプトを「デーモン」プロセスとしてチューニングするモジュールがすでに存在します(たとえば、Proc :: Daemon)。私はルビーの経験はありませんが、この記事はあなたを助けることができます。

デーモンプロセスは、システムの起動時にLaunchdを介して、またはログイン時のオートマトンアプリから、またはターミナルから手動で開始できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.