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][12], 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 sleeper
:
$ 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 proclaunch
and 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 run
as 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.