The maze book for programmers!
mazesforprogrammers.com

Algorithms, circle mazes, hex grids, masking, weaving, braiding, 3D and 4D grids, spheres, and more!

DRM-Free Ebook

The Buckblog

assorted ramblings by Jamis Buck

Tip: TextDrive and Lighttpd

11 February 2006 — 2-minute read

Here’s a tip if you’re running rails applications under lighttpd on TextDrive: don’t use static fcgi processes.

The static FCGI processes are the ones you get when you specify a bin-path in your configuration, a la:

1
2
3
4
5
6
7
8
9
10
fastcgi.server = ( ".fcgi" =>
    ( "localhost" =>
        (
          "min-procs" => 1,
          "max-procs" => 1,
          "bin-path" => "public/dispatch.fcgi",
          "bin-environment" => ( "RAILS_ENV" => "production" )
        )
    )
  )

There are two problems with doing it this way:

  1. Lighttpd doesn’t always like the way the Rails’ reaper process plays with its processes, so you sometimes need to restart lighttpd when deploying a new version of your application.
  2. Restarting lighttpd becomes extremely expensive, because all of the fastcgi processes get started up. With a single application that’s not a big deal, but if you start running more than one, you begin hating life when you have to restart lighttpd.

So, the solution?

First, create a tmp directory in your rails project.

Then, create a spawn script that looks something like this:

1
2
3
4
5
6
7
8
9
APP=yourapp
ROOT=/home/you/path/to/$APP
TMP=$ROOT/tmp
ENV=production

RAILS_ENV=$ENV spawn-fcgi -f $ROOT/public/dispatch.fcgi \
     -s $TMP/$APP-0.socket -P $TMP/$APP-0.pid
RAILS_ENV=$ENV spawn-fcgi -f $ROOT/public/dispatch.fcgi \
     -s $TMP/$APP-1.socket -P $TMP/$APP-1.pid</pre>

Go ahead and run this script. (What this does is spawn your fcgi processes externally. In this case, it spawns two processes, each listening on a different unix domain socket.)

Finally, tweak your lighttpd configuration so that it references the externally spawned fastcgi processes, instead of spawning directly:

1
2
3
4
fastcgi.server = ( ".fcgi" =>
   ( "localhost" =>
     ( "socket" => "/home/you/path/to/APP/tmp/APP-0.socket" ),
     ( "socket" => "/home/you/path/to/APP/tmp/APP-1.socket" )))

(Be sure to replace the paths with the correct paths that were specified in the spawn script.) Then, restart lighttpd. Lighttpd will balance requests between the sockets you specify, so you can specify as few or as many as you need. (The fewer you use, the happier the TextDrive staff will be.)

Now, you can use the Rails reaper command with confidence to restart your application, and restarting lighttpd is a very light, very inexpensive affair because your fastcgi processes are managed independently. You can now tweak your lighttpd configuration without fear!

(Note, however, that a reboot of the machine hosting your account will require you to run the spawn scripts for your applications again… I’m sure there’s a handy solution for that floating around somewhere, but I don’t know it offhand.)

Reader Comments

You might be able to use @reboot in your crontab to run the spawn script when cron starts up after a reboot.
Thanks for the tip. I was wondering why lighttpd would sometimes need to be manually started after a deploy.
Phil, the @reboot trick works perfectly. I'd heard of that before but had forgotten about it. Thanks for pointing it out! (Note to other readers--that feature only appears to exist in vixie cron.)
Jamis, you rock my world. How about sharing your switch tower recipe with us mere mortals? Cheers Koz
I made a "Rakefile":http://techno-weenie.net/svn/projects/misc/spawner/Rakefile to do some of this for you. The config is stored in a central yaml file. Great tip, thanks a lot!
koz, which ST recipe do you mean? The stuff in the article basically lets you use the default ST tasks without needing to create any custom ones--stuff like the @restart@ task should now work out of the box. rick, thanks for the rakefile!
RAILS_ENV should be in the beginning of the line: system "RAILS_ENV=#{conf['env']} ....." You could make crontab like this: @reboot /usr/local/sbin/lighttpd -f /users/home/roeland/etc/lighttpd.conf @reboot /usr/local/bin/rake -f /users/home/roeland/etc/fcgi/Rakefile spawn_all
Jakob: I fixed that. It's not running the command with RAILS_ENV in front though. Also, deploying requires me to kill lighttpd and the FCGI and respawn.
Strange, it works fine here. The only other thing I did is adding the full path to apps.yml
I've been trying to deploy my first Rails app, but the Switchtower page has been down for a couple of days...anyone else been able to get to it?
If anyone's interested, I fixed my stupid glitch in the "Rakefile":http://techno-weenie.net/svn/projects/misc/spawner/Rakefile. Rather than putting the environment at the beginning, I just set it with ENV['RAILS_ENV']. Lighttpd goes down hard whenever I try to gracefully reload. It seems each passing release gets worse...
Cool.
my spawn proceeses get killed when i restart lighty, can anyone plz tell what may be wrong?
bq. "Note, however, that a reboot of the machine hosting your account will require you to run the spawn scripts for your applications again… I’m sure there’s a handy solution for that floating around somewhere, but I don’t know it offhand." "Here is how":http://avlooks.net/articles/2006/06/15/managing-dispatch-fcgi-processed to set up FastCGI to run as a service accessible to every Rails domain user on a shared webserver.