Scheduling OSX jobs with launchd

Apple's preferred method of scheduling jobs is via launchd (rather than cron). One of the main benefits of using launchd is that jobs scheduled to occur while the machine was sleeping will run once it wakes up. This is different to cron where if the machine was sleeping the job just doesn't get executed.

The steps below give a practical example of how to schedule a script that performs a backup of photos to another machine on a daily basis.

The script to be scheduled is: /Users/paul/remoteSyncPictures.sh
It is just a simple script that rsync's the Photo Library to another machine as per below (assumes that keys have been configured for login):

rsync -av "/Users/paul/Pictures/Photos Library.photoslibrary" tv@macmini:"/Users/tv/Pictures/"  

We want to configure this script will run nightly (at 22:30) to backup the photo album.

To do this we need to define a launch agent. The launch agent is what tells OSX what to run and when. It is defined in an plist file (which is just an xml based configuration file). The plist file to be used for configuring the script is provided below for reference. The default location for storing per-user plist files (so they get picked up automatically) is: ~/Library/LaunchAgents. (Note that there are other locations for system wide agents). It is generally recommended that the name of the plist file match the Label defined in the definition so that it is easy to trace them (note that the labels need to be globally unique as well).

So the plist file is named

~/Library/LaunchAgents/com.thecruskit.remoteSyncPictures.plist

and contains:

<?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.thecruskit.remoteSyncPictures</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/paul/remoteSyncPictures.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>22</integer>
        <key>Minute</key>
        <integer>30</integer>
    </dict>
    <key>StandardErrorPath</key>
    <string>/Users/paul/remoteSyncPictures.log</string>
    <key>StandardOutPath</key>
    <string>/Users/paul/remoteSyncPictures.log</string>  
</dict>  
</plist>  

The example above schedules based on StartCalendarInterval so that the job runs at the same time each day. It is also possible to schedule based on StartInterval which will run the job with defined intervals between execution. The full range of properties that it is possible to configure for a job are captured in the Apple OSX launchd.plist man page

Once the configuration file has been created, it is necessary to load it. This is performed using the launchctl utility.

To load the job definition, use:

launchctl load ~/Library/LaunchAgents/com.thecruskit.remoteSyncPictures.plist

The job is now scheduled and will run at the desired time.

Once the job has been loaded, it can be manually triggered (rather than waiting for the scheduled time) by running:

launchctl start com.thecruskit.remoteSyncPictures

Check the status of scheduled jobs using:

launchctl list

To unload the job:

launchctl load ~/Library/LaunchAgents/com.thecruskit.remoteSyncPictures.plist

The full range of options available using launchctl can be found on the Apple OSX Man page for launchctl

Another useful reference on launchd is Nathan Grigg's Scheduling Jobs with launchd page. It provides a bit more background on launchd as well as options for GUI interfaces for configuring the jobs.