Mac OSX launchd 定时任务

除了工作里,生活中也有很多重复的任务。比如说定期查询户口办理状态,尽可能第一时间去办理下一步。所以需要有一种方法可以定时跑一个脚本去爬取查询网站,解析结果最后通知自己。在 Mac 上可以用 launchd。

在操作系统中除了我们手动打开关闭的应用程序,还有一类后台常驻的进程,叫做 service 或者 daemon,大部分系统服务都是常驻的,在命令行中通过 launchctl list 查看,大部分是以 com.apple 开头。我们自己也可以创建一个常驻任务加载到 launchd 中。例如 cleanmymac 就加在了一个定时启动的任务在我的系统里。可以说 launchd 是管理这些后台进程的后台进程。

创建一个 launchd 任务

创建一个任务非常简单,只要新建一个合法的 plist 文件,下面这个是为了实现上面提到的需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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>com.fengweizhou.scheduledJobs</string>
<key>ProgramArguments</key>
<array>
<string>/Users/fengweizhou/Documents/MyProjects/scheduledJobs/.build/release/scheduledJobs</string>
</array>
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>10</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<dict>
<key>Hour</key>
<integer>17</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
</array>
</dict>
</plist>

这个 plist 包含三个关键部分:

  1. 唯一标示 Label;// 也是 plist 文件名
  2. 运行的命令; // 上面这个例子中是我自己写的程序
  3. 运行时机;

运行时机可配置的选项很多,具体可以查看官方文档,这个例子中我想要在每天的早上10点半和下午5点半各运行一次我的爬虫程序。

加载 launchd 任务

将配置文件放入指定目录,我是放在用户目录下 ~/Library/LaunchAgents 也可以放在系统根目录的对应文件夹下,区别就是当前用户还是全体用户。放入后运行 launchctl load com.fengweizhou.scheduledJobs 然后 launchctl list 就可以看见自己的任务了,如果要立马运行一次可以使用 launchctl start

其他

每次修改了 plist 文件都必须 launchctl unload 再 load 进去,进行手动的 reload,才有效果

在文档中提到了,如果在任务设定的时间点系统是休眠的,那么任务会在休眠结束时执行一次。在我实际使用的过程观察到这个机制是有时间限制的,如果结束休眠的时间和任务设定时间相差不远会执行,但是如果相差很远就不会再执行。这和 iOS 上闹钟的行为是一摸一样的,再加上 iOS 和 OSX 系出同源,所以可以猜测 iOS 的闹钟实现是使用了 launchd,这也可以推论出另一个结果 iOS 上没法作出第三方功能强大的闹钟应用,因为沙盒限制。闹钟APP 还是安卓上的强。

参考

Daemons and Services Programming Guide

http://www.launchd.info/