Managing Your Processes with ProcLaunch.
Edit 2010-08-08: ProcLaunch now has a CPAN-compatible install process. See below for details.
I finally got the chance to work some more on proclaunch, my implementation of a user space process manager, like runit or mongrel or god. I wrote up a big overview of the currently available options [previously], but in summary: all of the existing options suck. They're either hard to setup, have memory leaks, have a weird configuration language, or are just plain strange. The only viable option was procer, and even that was just sort of a tech demo put together for the Mongrel2 manual.
That's why I started putting together proclaunch. I need some of the features of runit, namely automatic restart, with none of the wackyness, and I wanted it to be easy to automatically configure. I also wanted it to be standalone so I wouldn't have to install a pre-alpha version of Mongrel2 just to manage my own processes.
What of it?
Grab the latest version off of github, unpack it, and run this in the unpacked directory:
$ perl Build.PL $ ./Build $ ./Build install
If everything went smoothly you'll have
proclaunch somewhere in your path. Now, fire it up:
$ mkdir -p /path/to/some/state/directory $ sudo proclaunch \ --debug \ --foreground \ /path/to/some/state/directory \ example_profiles/
If everything goes according to plan, you'll see a bunch of debug info scroll past showing that it scanned the profiles directory, found one called
sleeper, and kicked it off. Then, every five seconds you'll see it rescan. If you look in your process list for
sleep you'll see bash happily kicking off a
sleep 10 in an infinite loop as the
nobody user. Now, run this:
$ sudo kill `cat /path/to/some/state/directory/proclaunch.pid`
You should still see the sleep going on, but
proclaunch shouldn't show up anywhere. If you launch
proclaunch again, you'll see it startup but never start
sleeper, since it's already running. This may seem really mundane, but you can't make runit behave this way without some major hacks. Oh, and to actually make
proclaunch kill everything before dying, kill it with -HUP:
$ sudo kill -HUP `cat /path/to/some/state/directory/proclaunch.pid`
Now for the automatic restart. Change something about the profiles directory:
$ touch example_profiles/
In the log you should see that
proclaunch saw something changed and rescanned immediately. Now change something about
$ touch example_profiles/sleeper
Within a few seconds,
proclaunch will notice that something happened and restart
sleeper. Specifically, it will send
sleeper's pid a
SIGTERM, wait up to 7 seconds for it to actually die, and then send it a
SIGKILL. Now something a little more drastic:
$ sudo mv example_profiles/sleeper example_profiles/sleeper2
proclaunch will notice that
sleeper is gone, tell it to stop, then start
sleeper2 since it obviously isn't running. You can use this to setup really simple deploys, especially if you're deploying with Capistrano. Just commit your profiles directory to version control and point
proclaunch at that directory in the
current symlink, making sure that the pid_file is within the deploy directory somewhere. Within 5 seconds of your deploy,
proclaunch will see that the inode on the profiles directory changed.
What is a profile, anyway?
If you look in the
sleeper directory, you'll see this set of files:
run pid_file user
run is a small script that
proclaunch expects to execute and have it return in short order, having backgrounded itself and written it's pid to the path contained in
pid_file. This forms the core of both
procer. Really simple to setup and automate, since there isn't any complicated config file to manage. The
user file is special to
proclaunch, and tells it what user to start
run as. By default,
proclaunch will start
root, which is generally not what you want.
procer can do some fun things that
proclaunch can't do yet, like manage dependencies between profiles. If there's any demand I'll work on adding that but I don't currently need it.
A small digression into Mac OS X
Initially I wanted to use Privilege::Drop from CPAN to drop privileges when spawning profiles. It's a really clean pure perl module that has no dependencies other than perl itself. It even does a bunch of sanity checking to ensure that the privileges you dropped to are specifically what you wanted to drop to. However, on OS X with perl 5.10, it seems that you can't drop a large number of auxiliary groups that Privilege::Drop doesn't know about, at least not in the way that it's currently written. That's why the code for dropping privileges is inlined in
App::ProcLaunch::Profile. It still checks to make sure that the group you tried to drop to is in the list, but it doesn't assert the list matches exactly what you wanted to do.