Run a launchd job after Time Machine backup

Solution 1:

A simple solution is to use the tmutil command to manually trigger the backup and follow it up with your process (as part of a shell script that does both these steps).

  • First, turn off automatic backups from System Preferences > Time Machine or using the command tmutil disable
  • Use tmutil startbackup --auto --block to trigger a backup once every hour (the --block option is required to make the execution wait until the backup is finished)
  • Follow this with launching your process

See man tmutil for more information on using Time Machine from the command line.

Solution 2:

Okay, so after setting up a launch agent to log information for a while I've come up with a combined solution.

Quite simply I created a launch-agent that watches the com.apple.TimeMachine.plist file for updates like-so:

 <?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>org.example.backupd</string>
    <key>ProgramArguments</key>
    <array>
        <string>do something</string>
    </array>
    <key>WatchPaths</key>
    <array>
         <string>/Library/Preferences/com.apple.TimeMachine.plist</string>
     </array>
 </dict>
 </plist>

This file is updated every time Time Machine performs a backup, and runs towards the end (during the cleaning up/finishing stage I believe). With this in mind it is possible to invoke a script with the above watch path that checks to see if backupd is still running; if it is then the script sleeps for a minute and checks again, repeating until backupd has finished, before proceeding with whatever it needs to do.

This now allows post-backup actions to be triggered such as performing secondary backups (in my case via rsync to a NAS), checking the size of the last backup and other handy things.

Anyway, this solution seems to be the best way to do it, as I couldn't find any path to watch that triggers reliably after a backup is complete, but this should run close enough to the end of a backup to be useful.