Using launchd on Mac OS X

launchd is Mac OS X 10.4′s replacement for init, cron, (x)inetd and all the various startup bits like /etc/init.d or /Library/StartupItems (as was the preferred way in Mac OS X up to 10.3.x). It’s all replaced with one supervisor daemon which controls the startup (and restart upon failure) of daemons, schedules regular running of tasks and other hoopy things. I’ve been reading a little about it at Introduction to Tiger Terminal part 5 and Getting started with launchd trying to figure out how to make it work for me. And I came up with settings, that will launch the Darwin Ports copies of both MySQL and PostgreSQL on demand, which you can download here: mysql4.plist and postgresql.plist. Place those files in /Library/LaunchDaemons and, to get launchd to notice them, run the following:

[code]mathie@Tandoori:mathie$ sudo launchctl unload /Library/LaunchDaemons Password: mathie@Tandoori:mathie$ sudo launchctl load /Library/LaunchDaemons[/code]

You should now have a couple of extra launch services to control, which you can see with:

[code]mathie@Tandoori:mathie$ sudo launchctl list [ ... ] mysql4 postgresql[/code]

In order to start MySQL and PostgreSQL, run the following:

[code]mathie@Tandoori:mathie$ sudo launchctl start mysql4 mathie@Tandoori:mathie$ sudo launchctl start postgresql[/code]

And to stop them, replace the start in the above example with stop. If either of the daemons happen to die horribly, they ought to be automatically restarted. It’s even smart about giving up restarting them if they fail 10 times in a short period. If you want to always start these daemons automatically at boot (I don’t, really, I just want to use them on demand occasionally), add the following inside the top-level dict in each of the plist files:

[code lang="xml"]RunAtLoad [/code]

You’ll need to repeat the unload/load sequence from above to reload the plist files, but you’ll notice that the MySQL and PostgreSQL daemons both start when the load command is issued (and also at system boot time).

Next, I would like to actually get MySQL and PostgreSQL to both start entirely on demand. It looks kinda like this should be possible with launchd, using the WatchPaths key. If I could tell it to watch for clients attempting to connect to the daemon’s socket, then magically start the daemon in question on demand, quitting it after it’s not needed, I could save quite a bit of system resources (particularly since I only really use PostgreSQL in a work capacity — most of my personal development projects use MySQL since that’s what my hosting company provides).

Unfortunately, I can’t quite see how to achieve this. Both the database daemons create sockets on the file system when they are launched. I had hoped that simply specifying this file name as a WatchPath would be enough. But since the sockets are only created when the daemons start, they aren’t pervasive on the file system and don’t exist for launchd to watch them the rest of the time. I do wonder if just creating an empty file and having launchd watch that would be enough, but I suspect not.

It would also appear the launchd doesn’t support any sort of dependency checking for daemons. Which is unfortunate, since the next task I was going to get it to do is manage the Zope instances on my laptop. However, in order to do this nicely, it would have been good to describe which instances use MySQL and which use PostgreSQL, then start up the relevant database before starting up the instance. Likewise, if the instance also needed a ZEO for the back end ZODB. But no, it doesn’t appear that we can do that — StartupItems provides that functionality instead. So launchd isn’t a complete replacement for its predecessors after all. Oh well.

8 thoughts on “Using launchd on Mac OS X

  1. Thanks mate! Am going to checkout the postgres plist since i’m using pykota and postgres with cups 10.4 server.

  2. What about the OnDemand key to get the databases to start and stop only when you want. I haven’t looked into it very closely, but I saw someone using a lighttpd server set OnDemand to false to ensure an auto-load.

  3. Thanks for this! There are quite a few false leads out there, but when I tried your solution it worked like a charm first time. Certainly saved me a lot of time and frustration.

  4. There’s no dependancy checking with launchd, but this is because it doesn’t need it. To quote from Apple’s “Getting Started with launchd” http://developer.apple.com/macosx/launchd.html:

    “You cannot specify dependencies and ordering for launchd jobs; instead, design daemons to wait for needed resources, or trigger them automatically. For instance, on a Linux system, you must specify that the portmap service is launched before the NFS server. The Mac OS X approach is to have portmap spawned automatically when a server tries to register with it.”

    If you set up launchd to run MySQL and Postgres on demand, you shouldn’t have to worry about getting them to run in the right order.

  5. Pingback: VelociPeek - Eric’s weblog on tech » OS X Leopard Startup Script for MySQL

  6. Looks like the .plist files are no longer available. Unfortunate because I’m trying to solve a similar problem.

  7. On demand loading of daemons can be accomplished with the “Socket” launchd key. The following example (added to the launchd plist) will monitor a network socket at port 3306 and the Unix socket used under the MacPorts install of MySQL:

    <key>Sockets</key>
    <dict>
        <key>MySQL-unix</key>
        <dict>
            <key>SockFamily</key>
            <string>Unix</string>
            <key>SockPathName</key>
            <string>/opt/local/var/run/mysql5/mysqld.sock</string>
        </dict>
        <key>MySQL-net</key>
        <dict>
            <key>SockFamily</key>
            <string>IPv4</string>
            <key>SockServiceName</key>
            <string>mysql</string>
        </dict>
    </dict>
    

    See http://www.macosxhints.com/article.php?story=20080128103022907 for another plist.