Mac miniサーバーで定期的にスクリプト処理を実行させたいケースが発生しました。
通常はcrontabを使うのですが、Macではlaunchdを使う方が良いとのことです。
crontabでも出来るとのことですが、アクセス権などの制限に引っかかる可能性があり、せっかくなのでlaunchdを使うことにしました。
目的
pythonスクリプトを定期的に実行するためのlaunchdの設定方法を記載します。
pythonスクリプトでは、外部のAPIを叩いてIPアドレスを取得し、取得したIPアドレスを元にDNSのAレコードを更新する処理を行います。
0. 環境
- Mac mini (macOS Ventura 13.6)
- Python 3.11.4
1. launchdの設定ファイルを作成する
設定方法は以下のフォルダにXML形式のplistファイルを作成します。
以下のFileNameは任意の名前で、拡張子はplistにします。
フォルダ | 説明 |
~/Library/LaunchAgents/<FileName>.plist | ユーザーレベルのlaunchdジョブ |
/Library/LaunchAgents/<FileName>.plist | システム全体のユーザーレベルのlaunchdジョブ |
/Library/LaunchDaemons/<FileName>.plist | システム全体のrootレベルのlaunchdジョブ |
上記の「ユーザーレベルのlaunchdジョブ」と「システム全体のユーザーレベルのlaunchdジョブ」はエージェントとなり、ユーザーがログインしているときに実行されます。
「システム全体のrootレベルのlaunchdジョブ」はデーモンとなり、ユーザーがログインしていないときでも実行されます。
今回のケースはサーバーのように使用しているため、ログインしていない時でも実行したいので、/Library/LaunchDaemons/<FileName>.plistに作成します。
2. plistファイルの作成
以下のような内容でplistファイルを作成します。
sudo vi /Library/LaunchDaemons/launched.python.dns.update.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>launched.python.dns.update</string>
<key>ProgramArguments</key>
<array>
<string>python</string>
<string>/Users/tomo/Scripts/python.com_dns_update.py</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>0</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/tomo/Develop/Scripts/python.com_dns_update/dice_script.out</string>
<key>StandardErrorPath</key>
<string>/Users/tomo/Develop/Scripts/python.com_dns_update/dice_script.err</string>
</dict>
</plist>
簡潔に上記のKeyを説明すると以下のようになります。
Key | 記述方法 | 説明 |
Label | 任意の名前 | launchdジョブの名前で、任意の名前を指定します。 |
ProgramArguments | 配列形式 | 実行するコマンドと引数を指定します。 |
StartCalendarInterval | 辞書形式 | 実行する時間を指定します。 |
StandardOutPath | ファイルパス | 標準出力の保存先を指定します。 |
StandardErrorPath | ファイルパス | 標準エラーの保存先を指定します。 |
今回は定期時間になったら実行するため「StartCalendarInterval」を使用しておりますが、以下のように実行するパターンが他にもあります。
- 「StartInterval」: 指定した秒数ごとに実行
- 「WatchPaths」: 指定したパスに変更があった場合に実行
- 「QueueDirectories」: 指定したパスにファイルが追加された場合に実行
- 「KeepAlive」: 指定したプロセスが終了した場合に実行
- 「StartOnMount」: 指定したボリュームがマウントされた場合に実行
このあたりは以下のWikipediaに記載があるようです。
https://ja.wikipedia.org/wiki/Launchd
またファイルの作成は直接作成する他に、以下のサイトから作成する事も可能です。
https://launched.zerowidth.com
3. plistファイルの権限を変更する
作成したplistファイルの権限を変更します。
sudo chmod 644 /Library/LaunchDaemons/launched.python.dns.update.plist
権限を変更した後、所有者をrootに変更します。
sudo chown root:wheel /Library/LaunchDaemons/launched.python.dns.update.plist
4. launchdを読み込み、定期処理を開始する
launchdにplistファイルを読み込ませます。
sudo launchctl load /Library/LaunchDaemons/launched.python.dns.update.plist
5. launchdの確認
launchdに読み込まれているか確認します。
sudo launchctl list | grep launched.python.dns.update
出力結果は以下のようになります。
- 0 launched.python.dns.update
6. launchdのアンロードして、定期処理を停止する
定期処理を行わないようにするには、launchdをアンロードします。
sudo launchctl unload /Library/LaunchDaemons/launched.python.dns.update.plist