Managing dispatch.fcgi processes
Posted by Andrew Thu, 15 Jun 2006 23:55:00 GMT
Rails committer Jamis Buck recently explained in this post why it is important not to use static FastCGI processes on shared webservers. AVLUX took Jamis’ helpful guidance and used it as a starting point to enable all its Rails hosting customers to manage their own FastCGI processes
At the end of this post Jamis writes:
“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.”
At AVLUX this is how we facilitate our Rails developers managing their own dispatch.fcgi processes, and ensuring that they all run at startup:
1) Create a startup script for FastCGI in /etc/rc.d/rc.fcgi
#!/bin/sh
curruser=$1
currdir=`pwd`
homeuser=`stat -c %U $currdir`
domdir=/var/www/vhosts
case $2 in
-d)
env=development
specific=true
;;
-t)
env=test
specific=true
;;
-p)
env=production
;;
*)
env=production
;;
esac
if [ "$curruser" = "root" ]; then
env=production
specific=false
fi
# Read through all domains
ls -1 $domdir | while read domain
do
# Check to for Ruby on Rails domains
if [ -d $domdir/$domain/rails/public ]; then
cd $domdir/$domain/rails
# Change to fully resolved directory (no symlinks) to keep Lighttpd happy
railsdir=`pwd -P`
cd $railsdir
# Get owner of current directory, in order to start fcgi processes as that user
owner=`stat -c %U .`
if [ "$curruser" = "root" -o "$curruser" = "$owner" ]; then
# Ensure that ownership is set correctly
echo Updating owner on $domain/rails dir contents to $owner
echo Rails dir is $railsdir
# chown -R $owner $railsdir/*
echo Starting dispatch.fcgi in processes in RAILS_ENV $env for $domain as user $owner...
# Create tmp/sockets dirs if they don't exist
if [ ! -d $railsdir/tmp ]; then
su $owner -c "mkdir tmp"
fi
if [ ! -d $railsdir/tmp/sockets ]; then
su $owner -c "mkdir tmp/sockets"
fi
sockdir=$railsdir/tmp/sockets
# Start FastCGI processes for domain
if [ "$curruser" = "$owner" ]; then
RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$domain-fcgi-0.socket -P $sockdir/$domain-fcgi-0.pid
RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$domain-fcgi-1.socket -P $sockdir/$domain-fcgi-1.pid
else
su $owner -c "RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$domain-fcgi-0.socket -P $sockdir/$domain-fcgi-0.pid"
su $owner -c "RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$domain-fcgi-1.socket -P $sockdir/$domain-fcgi-1.pid"
fi
echo ------------------------------------------------------
sleep 3
# Now check to for Ruby on Rails subdomains
ls -1 $domdir/$domain/subdomains | while read sub
do
if [ -d $domdir/$domain/subdomains/$sub/rails/public ]; then
cd $domdir/$domain/subdomains/$sub/rails
# Change to fully resolved directory (no symlinks) to keep Lighttpd happy
railsdir=`pwd -P`
cd $railsdir
# Get owner of current directory, in order to start fcgi processes as that user
owner=`stat -c %U .`
# Ensure that ownership is set correctly
echo Updating owner on $sub.$domain/rails contents to $owner
echo Rails subdir is $railsdir
# chown -R $owner $railsdir/*
echo Starting dispatch.fcgi processes in RAILS_ENV $env for $sub.$domain as user $owner...
# Create tmp/sockets dirs if they don't exist
if [ ! -d $railsdir/tmp ]; then
su $owner -c "mkdir tmp"
fi
if [ ! -d $railsdir/tmp/sockets ]; then
su $owner -c "mkdir tmp/sockets"
fi
sockdir=$railsdir/tmp/sockets
# Start FastCGI processes for subdomain
if [ "$curruser" = "$owner" ]; then
RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$sub.$domain-fcgi-0.socket -P $sockdir/$sub.$domain-fcgi-0.pid
RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$sub.$domain-fcgi-1.socket -P $sockdir/$sub.$domain-fcgi-1.pid
else
su $owner -c "RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$sub.$domain-fcgi-0.socket -P $sockdir/$sub.$domain-fcgi-0.pid"
su $owner -c "RAILS_ENV=$env spawn-fcgi -f $railsdir/public/dispatch.fcgi \
-s $sockdir/$sub.$domain-fcgi-1.socket -P $sockdir/$sub.$domain-fcgi-1.pid"
fi
echo ------------------------------------------------------
sleep 3
fi
done
# Start Lighttpd server by user
/usr/local/bin/lighttpd_server start $owner
fi
fi
done
2) Set up FastCGI to run as a service, by creating /etc/init.d/fcgi
#!/bin/bash
#. /etc/rc.d/init.d/functions
PATH=/sbin://bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin:/usr/local/bin
prog=dispatch.fcgi
proc=dispatch.fcgi
startup=/etc/rc.d/rc.fcgi
startarg=$2
owner=`whoami`
currdir=`pwd`
start() {
if [ "$owner" = "root" ]; then
echo "Attempting to start $prog for all users..."
bash $startup $owner; echo -e "OK";
else
if [ "$startarg" = "" -o "$startarg" = "-d" -o "$startarg" = "-t" ]; then
echo "Starting $prog for user '$owner'... "
if `pgrep -u $owner -f $proc 1>/dev/null 2>/dev/null`; then
bash $startup $owner $startarg; echo -e "OK";
echo "$prog for user '$owner' is already running..."
else
bash $startup $owner $startarg; echo -e "OK";
fi
else
echo $"Usage: $prog {start [-d, -t] |stop|restart|status}"
exit 1
fi
fi
}
stop() {
if [ "$owner" = "root" ]; then
echo "Stopping $prog for all users..."
pkill -9 -f $proc
echo -e "OK";
else
echo -n $"Stopping $prog for user '$owner'..."
if ! `pgrep -u $owner -f $proc 1>/dev/null 2>/dev/null`
then
echo "$prog for user '$owner' is not running";
else pkill -9 -u $owner -f $proc
echo -e "OK";
fi
fi
}
status() {
if [ "$owner" = "root" ]; then
if `pgrep -f $proc 1>/dev/null 2>/dev/null`;
then
echo "$proc processes running on `pgrep -d , -f $proc`";
pgrep -f $proc -l
else echo "$prog is not running...";
fi
else
if `pgrep -u $owner -f $proc 1>/dev/null 2>/dev/null`;
then
echo "$proc processes for user '$owner' running on `pgrep -u $owner -d , -f $proc`";
pgrep -u $owner -f $proc -l
else echo "$prog for user '$owner' is not running...";
fi
fi
}
case "$1" in
start)
start
status
;;
stop)
stop
status
;;
restart)
stop
start
status
;;
status)
status
;;
*)
echo $"Usage: $prog {start|stop|restart|status}"
exit 1
esac
3) Add this line to /etc/rc.d/rc.local
/etc/init.d/fcgi startOf course your lighttpd.conf files must be written accordingly, e.g.
server.modules = ("mod_rewrite","mod_redirect","mod_access"
,"mod_status"
,"mod_fastcgi"
,"mod_proxy"
,"mod_accesslog"
)
var.vhosts = "/home/httpd/vhosts/"
var.domain = "yourdomain.com"
server.bind = domain
server.port = 4004
server.pid-file = vhosts + domain + "/var/run/lighttpd.pid"
server.username = "username"
server.groupname = "groupname"
status.status-url = "/server-status"
server.indexfiles = ( "index.html", "dispatch.fcgi" )
server.document-root = vhosts + domain + "/rails/public"
server.error-handler-404 = "/dispatch.fcgi"
fastcgi.server= (".fcgi" => ( domain =>
( "socket" => vhosts + domain + "/rails/tmp/sockets/" + domain + "-fcgi-0.socket" ),
( "socket" => vhosts + domain + "/rails/tmp/sockets/" + domain + "-fcgi-1.socket" )
) )







