class Monstar

June 5th, 2009

I recently had to move from using FastCGI on Camping Ruby framework, to sweet Mongrel because of getting too much 500 HTTP errors under some load tests. Yes irc::zimbatm, me too.
When on FastCGI behing Lighttpd, upon each request, the code is loaded so after changing its source, it gets updated.

Now, under development, Mongrel(s), behind the same Lighttpd frontend, need to be restarted upon source code changes in the models, views, controllers or helpers (yet not CSS files, since they are taken care by lighty). Instead of moving to the xterm, kill the process and restart it i decided to automate it.
Since i was disconnected from the webz, I’ve done this script to detect file changes from a pre-specified array of files, monitored under a certain interval in seconds, with an action to start, kill, and restart an app (in my case, a Mongreled Camping web app).

Problem: Threads
Solution: Process::fork

The app load (in this case I load/execute ruby scripts) is done via Process::fork. A new process starts up each time this method is fired up upon a, 'r').ctime change:

def load_app
 @pid = Process.fork { load(@app) }

Before loading up a new updated instance of the app, the previous one must be terminated. Threads behaviour was problematic because of the thread tree termination in time. This is well done, in a safe mode, with Process::kill(signal, pid) and Process::wait(pid) that waits the pid process termination, essential in the case of Mongrel server.

def kill_app
  Process.kill("KILL", @pid)

As one can see jump to flickr in this screenshot the main app process holds on while the child, in this case our Mongrel’ed Camping web app, is terminated and created a new one. jump to flickr Verbose mode to assert its behaviour. Suits this specific need.

This is very usefull to make tests (Test::Unit:TestCase) run automatically upon source changes (will get to an Autotest clone).

Changing from load(@app) to system(@app), one can get any command be executed. ftp, cp, etc…

The script is here do download under a Ruby License.

Usage: monstar [options]
-a, --app SCRIPT.RB,PARAMS,...
-i, --interval VAL
-f, --files FILE,FILE1,...
-h, --help