launchdで定期的にスクリプトを実行

  • 29
    いいね
  • 0
    コメント

定期的にスクリプトを実行する場合、Mac OS Xではcrontabよりlaunchdを使うことが推奨されている。
launchdを用いてMac OS Xで定期的にスクリプトを実行する方法を記述。

特徴

  • 設定が2種類ある:
    • エージェントはユーザーがログイン中に実行できるプログラム。
    • デーモンはシステム共通で、誰もログインしていなくても実行できるプログラム。
  • 前回の実行が終わらないと次の実行は始まらない。また、スリープ状態、シャットダウン状態では実行されない。1
  • 標準でCPU時間メモリファイル等の使用の制限2が設けられている。必要に応じて設定ファイルで上限を上げないと、シグナルで届いてしまう。

設定ファイルを置く場所は次の通り。

場所 用途
~/Library/LaunchAgents/<Label>.plist ユーザーごと設定できるエージェント
/Library/LaunchAgents/<Label>.plist 管理者用のエージェント
/Library/LaunchDaemons/<Label>.plist システム共通のデーモンrootがオーナー)

Label はユニークな識別名。ファイルはplist形式3

単純なサンプル

一定間隔で実行と、特定の時間に実行する方法がある。

10秒間隔でスクリプトを実行

次を満たすサンプルを作る。

  • 実行するのは一般ユーザー所有のスクリプト:test.rb
  • 10秒ごとに実行するエージェントとして設定する。
  • STDOUT/STDERR出力をファイルに保存(test.out/test.err)。

識別名(Label)はtestにするので設定ファイルはtest.plist
一般ユーザー所有のエージェントスクリプトなので~/Library/LaunchAgents/に置く。

設定ファイル:~/Library/LaunchAgents/test.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//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>/usr/bin/ruby</string>
        <string>-Ku</string>
        <string>/Users/mofu/script/test.rb</string>
    </array>
    <key>StartInterval</key>
    <integer>10</integer>
    <key>StandardOutPath</key>
    <string>/Users/mofu/script/test.out</string>
    <key>StandardErrorPath</key>
    <string>/Users/mofu/script/test.err</string>
</dict>
</plist>

次のコマンドで登録すると、実行されるようになる。

$ launchctl load ~/Library/LaunchAgents/test.plist

これ以降、システムを再起動してもこのユーザーでログインすれば設定が維持され、実行が再開する。
登録解除するには次のコマンドを使う。

$ launchctl unload ~/Library/LaunchAgents/test.plist

これ以降、実行されなくなる。

毎日、0時0分にスクリプトを実行

次を満たすサンプルを作る。

  • 実行するのは一般ユーザー所有のスクリプト:test2.rb
  • 毎日、0時間0分に実行するエージェントとして設定する。
  • STDOUT/STDERR出力をファイルに保存(test2.out/test2.err)。

識別名はtest2とするので設定ファイルはtest2.plist
一般ユーザー所有のエージェントスクリプトなので~/Library/LaunchAgents/に置く。

設定ファイル:~/Library/LaunchAgents/test2.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test2</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/ruby</string>
        <string>-Ku</string>
        <string>/Users/mofu/script/test2.rb</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>0</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/Users/mofu/script/test2.out</string>
    <key>StandardErrorPath</key>
    <string>/Users/mofu/script/test2.err</string>
</dict>
</plist>

次のコマンドで登録。

$ launchctl load ~/Library/LaunchAgents/test2.plist

用途ごとサンプル

iOSアプリのデイリービルドデーモン

次を満たすサンプルを作る。

  • スクリプトbuild.shをシステム共通で(ログインしていない状態でも)実行できるようにする。
  • すなわちデーモンとして設定する。実行するタイミングは毎日0時間0分。
  • デーモンとして設定するのでroot所有の設定だが、スクリプトの実行ユーザーはmofuとする。
  • 各種制限に引っかからないよう、上限を設定する。
    • 処理時間:1,200秒(標準は20秒である)。
    • CPU時間:1,200秒。
    • 最大メモリ:2,000,000,000バイト。
    • 最大ファイルサイズ:2,000,000,000バイト。
  • 環境変数を設定:CocoaPodsのpod installのためLC_ALLen_US.UTF-8に。
  • ワーキングディレクトリを/Users/mofu/scriptに設定。
  • STDOUT出力をファイルに保存(build.out)。

識別名はbuildとするので設定ファイルはbuild.plist
システム共通のデーモンスクリプトなので/Library/LaunchDaemons/に置き、rootを所有者にする。

設定ファイル:/Library/LaunchDaemons/build.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>build</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/mofu/script/build.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>0</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/Users/mofu/script/build.out</string>
    <key>WorkingDirectory</key>
    <string>/Users/mofu/script</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>LC_ALL</key>
        <string>en_US.UTF-8</string>
    </dict>
    <key>UserName</key>
    <string>mofu</string>
    <key>SessionCreate</key>
    <true />
    <key>ExitTimeOut</key>
    <integer>1200</integer>
    <key>SoftResourceLimits</key>
    <dict>
        <key>CPU</key>
        <integer>1200</integer>
        <key>FileSize</key>
        <integer>2000000000</integer>
        <key>Data</key>
        <integer>2000000000</integer>
    </dict>
    <key>HardResourceLimits</key>
    <dict>
        <key>CPU</key>
        <integer>1200</integer>
        <key>FileSize</key>
        <integer>2000000000</integer>
        <key>Data</key>
        <integer>2000000000</integer>
    </dict>
</dict>
</plist>

次のコマンドで設定ファイルのオーナーをrootにし、登録する。

$ sudo chown root /Library/LaunchDaemons/build.plist
$ sudo launchctl load /Library/LaunchDaemons/build.plist

※iOSビルドスクリプトについてはこちらに記述。

平日のみ、毎日10時にスクリプトを実行

次を満たすサンプルを作る。

  • スクリプトweekdays.shをデーモンとして実行する。
  • 実行するタイミングは平日のみ、毎日10時。
設定ファイル:/Library/LaunchDaemons/weekdays.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>weekdays</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/mofu/script/weekdays.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Weekday</key>
            <integer>1</integer>
            <key>Hour</key>
            <integer>10</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Weekday</key>
            <integer>2</integer>
            <key>Hour</key>
            <integer>10</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Weekday</key>
            <integer>3</integer>
            <key>Hour</key>
            <integer>10</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Weekday</key>
            <integer>4</integer>
            <key>Hour</key>
            <integer>10</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Weekday</key>
            <integer>5</integer>
            <key>Hour</key>
            <integer>10</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
    </array>
</dict>
</plist>

次のコマンドで設定ファイルのオーナーをrootにし、登録する。

$ sudo chown root /Library/LaunchDaemons/weekdays.plist
$ sudo launchctl load /Library/LaunchDaemons/weekdays.plist

設定項目の一覧

定期的にスクリプトを実行するために使う設定。

識別名【必須】

ジョブを識別するためのユニークな文字列で構成された識別名Labelに指定する。
ファイル名にもこの文字列を使う。

Label
<key>Label</key>
<string>mofu.build.daily</string>

何を実行するか【必須】

ProgramArgumentsに、実行するプログラムパラメータを指定する。

ProgramArguments
<key>ProgramArguments</key>
<array>
    <string>/bin/bash</string>
    <string>/Users/mofu/script/build.sh</string>
</array>

いつ実行するか

一定間隔ならStartInterval秒数を指定する。

StartInterval
<key>StartInterval</key>
<integer>10</integer>

特定の時間に実行するならStartCalendarIntervalに時間を指定する。

  • Minute
  • Hour時間
  • Day
  • Weekday曜日(0と7は日曜日)
  • Month
StartCalendarInterval
<key>StartCalendarInterval</key>
<dict>
    <key>Hour</key>
    <integer>0</integer>
    <key>Minute</key>
    <integer>0</integer>
</dict>

複数の時間を指定することもできる。

StartCalendarInterval、配列
<key>StartCalendarInterval</key>
<array>
    <dict>
        <key>Hour</key>
        <integer>10</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <dict>
        <key>Hour</key>
        <integer>19</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
</array>

どの環境で実行するか

WorkingDirectoryワーキングディレクトリを指定できる。

WorkingDirectory
<key>WorkingDirectory</key>
<string>/Users/mofu/script</string>

EnvironmentVariablesに、環境変数を指定できる。

EnvironmentVariables
<key>EnvironmentVariables</key>
<dict>
    <key>LC_ALL</key>
    <string>en_US.UTF-8</string>
</dict>

UserNameに、スクリプトを実行するユーザーを指定できる。

UserName
<key>UserName</key>
<string>mofu</string>

そのユーザーのセッションを作成した上で実行したい場合はSessionCreateを指定できる。(デーモンでもログインキーチェインが使える状態になる。)

SessionCreate
<key>UserName</key>
<string>mofu</string>
<key>SessionCreate</key>
<true />

処理時間の制限

ExitTimeOutに処理の制限時間秒数で設定できる。標準は20秒。
この時間が経過するとプロセスにSIGKILLシグナルが送られる。

ExitTimeOut
<key>ExitTimeOut</key>
<integer>1200</integer>

リソースの制限

SoftResourceLimitsHardResourceLimitsに、ソフト制限、ハード制限を設定できる。
ソフト制限を超えるとプロセスにシグナルが送られるがハート制限未満までなら実行を続けられる。
主な設定項目4

  • CPU:各プロセスに使用される最大CPU時間(秒)。
  • Data:使用できる最大メモリ(バイト)。
  • FileSize:作成できるファイルの最大サイズ(バイト)。
SoftResourceLimits、HardResourceLimits
<key>SoftResourceLimits</key>
<dict>
    <key>CPU</key>
    <integer>1200</integer>
    <key>FileSize</key>
    <integer>2000000000</integer>
    <key>Data</key>
    <integer>2000000000</integer>
</dict>
<key>HardResourceLimits</key>
<dict>
    <key>CPU</key>
    <integer>1200</integer>
    <key>FileSize</key>
    <integer>2000000000</integer>
    <key>Data</key>
    <integer>2000000000</integer>
</dict>

参照


  1. スリープの場合、スリープ中に実行するタイミングが来ていた場合、スリープから復帰したときに直ちに実行される。 

  2. 処理時間、CPU使用時間、メモリ、スタック、同時に開くファイル数、ファイルサイズ等。 

  3. Property List、XML形式。テキストエディタで編集可能。 

  4. 必要に応じて設定できる他のキー:CoreMemoryLockNumberOfFilesNumberOfProcessesResidentSetSizeStack。