Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

定期的にスクリプトを実行する場合、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。 

rsahara
プラグマティスト
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした