Launchd example: Start web server at boot-time

The blog-drought over the last month has been largely due to a big project at work, which has now gone live! *

The project was basically an order form, with various smarts to filter questions based on customer type, adhere to company business rules, etc.  In the process of designing and developing the form, and getting client feedback, we found we needed a means to track issues, bugs, and feature requests that was more robust than email.  After quickly reviewing several issue tracking options (HP Quality Center, ActiveCollab, trac, Mantis).  We decided to try Redmine, mostly because it seemed easy to install (it was), supports the issue management process for our needs, supports multiple projects and LDAP authentication out of the box.

I’ve installed Redmine on my local Mac Pro workstation, and was running it through the command line in Terminal.  The problem with that, of course, is that if I close that Terminal window, or log out of my computer, I terminate Redmine and no one else can use it.  Redmine allows you to run it as a daemon – an always running process – (ruby script/server webrick -d -e “production” ).

I think, however, the more ‘Mac Approved’ way to to this is to use launchd, which is Apple’s attempt to standardize long-running and/or timed processes.  Basically they’re using launchd to replace a host of unixy tools like cron, rc.d, etc.  An additional benefit is that it can also restart a job if for some reason it dies.

launchd looks for a configuration file in plist format in one of several places on your hard drive (see the launchd man page).  That config file tells launchd which program to run, any program arguments, whether it should run continuously or on demand, how often it should run, and a whole host of other  things.  Here’s my plist file for redmine:

<?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>KeepAlive</key>
<true/>
	<key>Label</key>
	<string>org.act.communications.website.redmine</string>
	<key>ProgramArguments</key>
	<array>
		<string>ruby</string>
		<string>script/server</string>
		<string>webrick</string>
		<string>-e</string>
		<string>production</string>
	</array>
	<key>QueueDirectories</key>
	<array/>
	<key>RunAtLoad</key>
<true/>
	<key>StandardErrorPath</key>
	<string>log/error.log</string>
	<key>StandardOutPath</key>
	<string>log/access.log</string>
	<key>WatchPaths</key>
	<array/>
	<key>WorkingDirectory</key>
	<string>/Users/Jerry/code/redmine/</string>
</dict>
</plist>

If I might paraphrase, that XML file tells launchd:

  • this job will be called org.act.communications.website.redmine
  • Run the process on system load (RunAtLoad=true key)
  • If the process dies, bring it back to life (the KeepAlive =true key)
  • Change the working directory to /Users/Jerry/code/redmine
  • Run the program arguments (ruby script/server webrick -e production)
  • send StandardOut and StandardError to the appropriate log files

By saving this file in one of the directories launchd monitors (in this case, /System/LaunchDaemons), launchd automatically reads the plist file and starts the program.  Pretty straightforward, except that its not fun to write/edit XML plist files by hand.  Not to worry, there are at least two launchd gui programs.  I picked Lingon, mostly because I found it first.

* I’ve been a professional programmer/developer/designer for nearly 10 years.  Almost all my work to date have been on non-public, internal applications for clients.  This may be my first work that 1) is publically viewable, and 2) meant for a large audience.

About these ads

One thought on “Launchd example: Start web server at boot-time

  1. Pingback: Launchd: Auto-starting ruby processes and keeping them alive | Seattle Publishing

Comments are closed.