Using launchd to run scheduled jobs

2011/08/29 14:25:22

My new server’s predecessor ran Linux. I had a few scheduled jobs, like the ones that back up this blog, its database, and so on. On Linux the tool used for scheduling jobs is cron. Lo and behold, Apple has deprecated cron on their systems in lieu of an Apple-grown tool named launched. Launchd’s job is to replace cron, init, the rc scripts, the file alteration monitor, and a whole host of other normal Unix utilities in favor of one huge behemoth process that starts at boot. I’ve got mixed feelings about this concept, as it goes against the Unix philosophy of “doing one thing and doing it well”, but I chose OSX and have tried to learn their way of doing things.

I found several articles describing how one creates the plist files used by launchd. These XML files contain the information on the process you wish to run, including when to run it, how to run it, and who is allowed to run it. Here I will detail how I used it to merely run a scheduled job every night at midnight.

To start with, I have a simple script that backs up the database on the server:

#!/bin/sh
 
BACKUPDIR=$HOME/Backups/lawrence.littleprojects.org/db
REMHOST=lawrence.littleprojects.org
OUTPUTFILE=$REMHOST.sql
 
# if we don't have a backup directory, make it
if [ ! -e $BACKUPDIR ]; then
  mkdir -p $BACKUPDIR
fi
 
cd $BACKUPDIR
 
# run the remote database dump command
ssh $REMHOST "mysqldump --verbose --user=root --password='XXXXXXXXXXXX' --all-databases" > $OUTPUTFILE
 
# if the zipped output file already exists, move it before zipping the new one
if [ -f $OUTPUTFILE.bz2 ]; then
  mv $OUTPUTFILE.bz2 old-$OUTPUTFILE.bz2
fi
bzip2 $OUTPUTFILE
 
chown smj:staff $OUTPUTFILE.bz2

This script is creatively entitled backup-database. I want it to run every night so I have an exact copy of this website’s database in case the web server goes down and I have to reinstall everything.

Under cron, I would run crontab -e and then put the following line into the editor that is brought up:

0 * * * *    $HOME/bin/backup-database

Apple made this simple step a lot more complicated than, in my opinion, it needed to be; but they gave me a tool that is a lot more powerful that mere cron.

To use launchd, I needed to make a file in the directory /Library/LaunchDaemons named org.littleprojects.backup.lawrence.db.plist that contains the following XML code:

<!--?xml version="1.0" encoding="UTF-8"?-->
 
 
 
    Label
    org.littleprojects.backup.lawrence.db
    ProgramArguments
 
        /Users/smj/bin/backup-database
 
    StartCalendarInterval
 
        Hour
        0
        Minute
        0

I’m a little annoyed at how Apple handled the whole key-value syntax, but I’ll let that be. The file reads as follows: create a job named org.littleprojects.backup.lawrence.db that will run the program /Users/smj/bin/backup-database at the 0th hour and 0th minute of ever day (midnight). I’m not sure if this is any less difficult to read than the cron syntax, but it is more difficult to write to be sure.

Once I created the file, I then needed to load it into launchd, which could be done by running the following commands:

sudo launchctl load org.littleprojects.backup.lawrence.db.plist

If you do this you, do not need to reboot as others claim. This is Unix and reboots should only be necessary for major operating system changes. Rebooting in order to create a scheduled job is not only ridiculous, but time-wasting and leads to error-prone behavior like making many untested scheduled jobs at once in order to save on reboots. I always try to find a way around reboots to avoid error-prone behaviors!

So, I did the same thing for other scripts I wanted to run at certain times. I understand why apple decided to use launchd, I just wish they would have made it easier to configure. Lingon exists in the app store for the express purpose of helping you create these plist XML files, but it will not load them for you and instead recommends you reboot after each edit, which I noted my distaste for above.

In the future I will be exploring how to best use launchd for other purposes, like restarting services, and scheduling scripts to run when other system events occur.

References:

Randomly crashing Mac Mini Server running Lion [Solution]

2011/08/18 19:08:24

I’d been looking for a home server solution that offered me more disk space, but that ran cool and quieter than my server-closet behemoth. I wanted the server to also be able to execute scripts and scheduled jobs. I researched several options, including the Dell Zino, but none seemed to capture my attention like the Mac Mini Server.

The day it arrived, I set it up and spent hours pouring over Apple’s documentation. I got file sharing, SSH, WebDAV, and other services set up easily, but realized that I had to download Server Admin Tools separately in order to get access to DHCP and DNS. Some admins speculate that this is a separate download to prevent would be admins from accidentally turning on DHCP in a network that already had it. Screen sharing worked flawlessly. I had it using my 46″ television as a monitor, so watching online video and iTunes was awesome!

The next day I went back to my new toy, and… it had locked up. I was not pleased. Murmuring curses and threats of sending the server back didn’t bring the server back from its limbo. This was UNIX! UNIX was not supposed to do this! I felt betrayed by a company I’ve been growing in support for. Why did they do this to me?

I think I’ve solved the problem. Nothing useful was in the logs, but I came across a forum post where someone had suggested that there were bugs [1][2] in Lion’s display drivers that caused some Macs to lock up when returning from sleep.

I went into System Preferences, then chose Energy Saver. I slid the slider next to Display Sleep all the way to the right, choosing Never. I have not had a lockup since.

I can’t recommend this for everyone, because they don’t have a display that is either off, or using another input, like my TV, but it might work in a pinch if you don’t mind manually turning your display off. Also, I’m a little surprised that it’s affecting my brand new Mac Mini Server, because the articles I’ve found refer to older Macs.

Update: This may have been fixed by the 10.7.1 patch. I haven’t tested it yet.