running your app in production as rc.d daemon

435 views
Skip to first unread message

hans

unread,
Mar 27, 2006, 6:26:56 PM3/27/06
to TurboGears
I have blown untold hours trying to find a statement of best practice
for actually running cherrypy in a production installation to NO avail
(unless you want the httpd mod_rewrite, which I don't).
start-stop-daemon doesn't fly, because it appears to have been retired
to oblivion. What I have desired to find is a clean scenario for
starting a turbogears app on linux without need for a controlling
terminal and restarting it on boot, using the rc.d sysinit scripts
methodology. BASIC. I have not been able to find anything of substance.
Guys, this should be in the most elementary cut of the docs. Come on.
This just to note that the documentation around turbogears is almost
unbelievably dissipated. Where does a person go for canonical docs??
IRC? Trak? Wiki? 'Doc' section of site? Every little component site,
etc??

So, for the love of every other non-expert-unix-system-programmer that
has given turbogears a try and hit this problem, here are my notes on
it. I hope they help someone. (incidentally, I got ZERO feedback from
the irc channel which really stunned and disappointed me (my question
was 'where is the best place to go for documentation?')).

The environment:
Fedora Core 4
PostgreSQL 8.1.3
Python 2.4.1
TurboGears-0.8.9-py2.4
psycopg2

working on production config ...
http://www.turbogears.org/docs/deployment/config.html
http://www.cherrypy.org/trunk/docs/book/chunk/ch03.html#id3060952
http://www.cherrypy.org/trunk/docs/book/chunk/ch03s02.html#id3139886

attempting like mad to create an init.d script for this crap ...

> Should there be a start-stop-daemon file somewhere on the system ?? In which Package ?

Have a look at Fedora init scripts: what Fedora uses is "daemon" which
is a function defined in /etc/init.d/functions. So adjust the code you
found in your iptables log analyzer source.
<<<<

confirming this ... ok. there is said functions file with 'daemon'
defined. not
sure how to use it. PID file will be a problem in any case. The pid
hack, below , is only a minimal start to a working solution.

(here is a link to start-stop-daemon download??
http://www.linuxfromscratch.org/download/ssd-0.4.1-lfs.tar.gz)
Crazy. circa 2000 link dead as a doornail. Can't find start-stop-daemon
references on the net after ~2004. Debian has a package called 'daemon'
http://packages.debian.org/stable/utils/daemon, but the maintainer
hasn't
posted changes since 04...Marc

Article on init scripting:
http://enterprise.linux.com/enterprise/05/08/02/1821218.shtml?tid=129
init script stub from fedora:
/usr/share/doc/initscripts-8.11.1/sysvinitfiles

[root@www conf]# cp /usr/share/doc/initscripts-8.11.1/sysvinitfiles .
[root@www conf]# mv sysvinitfiles jrd_marketing_web.init.d

added this to conf/ in repos ... ok r301

from turbogears google group:
What's stumping me now is that my TurboGears app, when it starts, does
> not write out a .pid file or anything of the like, so I'm not sure what
> the proper way is for my rc script to shut the server down when I tell
> it to.

> Does anyone have any hints on how to make this work? Do I need to
> subclass and add functionality to the server class in order to do this?

quick fix: add these lines to your application-start.py (assuming you
used quickstart)

import os
pid = file('app.pid', 'w')
pid.write(str(os.getpid()))
pid.close()

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
http://starship.python.net/~jjkunce/

looks like 'daemonize.py' is the python technique to use. what a
blazing pain.
turning off autoreload in the prod.cfg ... ok (seems to speed up
things.
still bloody slow on a blitzing new dedicated svr)

progress! apparently, the daemonize.py does not pass arguments given to
commands called! Lovely. Instead, when I hard code the paths, etc in
the
jrd_marketing_web-start.py, the thing works.

[root@www jrd_marketing_web]# ./daemonize.py -o ~/out
"/var/www/jrd_marketing_web/jrd_marketing_web-start.py"

now, to see if it can be worked in the init script ...

Matthew Bevan

unread,
Mar 27, 2006, 6:45:16 PM3/27/06
to turbo...@googlegroups.com
The initscript I use for Gentoo is really quite simple - I modeled it off of
the dbus initscript (though it does use start-stop-daemon, so does every
other Gentoo daemon) and only suffers a few problems. Like forking (thus the
-b). And not storing the actual PID of the running server so it can be
killed later. Once it goes live I'll need to re-write it for Fedora anyway.

---

#!/sbin/runscript

start() {
ebegin "Starting TurboGears application server"

start-stop-daemon --start --pidfile /var/run/tg.pid -m -b \
--exec /usr/local/bin/start-topfloor.py

eend $?
}

stop() {
local retval

ebegin "Stopping TurboGears application server"

start-stop-daemon --stop --pidfile /var/run/tg.pid
retval=$?

eend ${retval}

# This should vanish when baselayout-1.12.0 is marked stable.
[[ -f /var/run/tg.pid ]] && rm -f /var/run/tg.pid

return ${retval}
}

Rune Hansen

unread,
Mar 28, 2006, 1:38:51 AM3/28/06
to turbo...@googlegroups.com
Hi Hans,
Sorry to have missed your original question. This is the init script
I use for my redhat based servers(readhat/ES/Fedora/Centos).
The script is chkconfig compatible and offers stop, start and status.

/rune
---------------------------------------------------------------------
Behind the firewall, nobody can hear you scream...

---
#!/bin/sh

# Comments to support chkconfig on RedHat Linux
# chkconfig: 35 96 96
# description: Cherrypy start/stop script

. /etc/init.d/functions

python=/absolute/path/to/python/binary
server=Your_start_script.py
serverdir=/absoulte/path/to/your/server/dir
serverpidfile=$serverdir/Your_applications_pid.pid
serverlog=$serverdir/your_std_out_log.log

[ -x $python ] || exit 0

RETVAL=0

start () {
echo "Starting $server: "
if test -f $serverdir/$server
then
cd $serverdir
$python $server >> $serverlog 2>&1 &
RETVAL=$?
else
RETVAL=1
fi
start_success_or_fail $RETVAL
return $RETVAL
}

stop() {
if test -f $serverpidfile
then
serverpid=`cat $serverpidfile`
kill -15 $serverpid
rm -f $serverpidfile
RETVAL=$?
else
RETVAL=1
fi
stop_success_or_fail $RETVAL
return $RETVAL
}

start_success_or_fail(){
if [ $RETVAL -eq 1 ]; then
echo -n "Can't start $server"
echo_failure
echo
else
echo -n $server "started"
echo_success
echo
fi
}

stop_success_or_fail(){
if [ $RETVAL -eq 1 ]; then
echo -n "Killing $server"
echo_failure
echo
else
echo -n "Killing $server"
echo_success
echo
fi
}

status() {
local base=${1##*/}
if test -f $serverpidfile
then
pid=`cat $serverpidfile`
checkpid $pid
RETVAL=$?
else
RETVAL=1
fi
if [ $RETVAL -eq 0 ];then
echo "$server pid($pid) is running..."
return 0
else
if [ -f /var/run/${base}.pid ] ; then
read pid < /var/run/${base}.pid
if [ -n "$pid" ]; then
echo $"${base} dead but pid file exists"
return 1
fi
fi
echo $"${base} is stopped"
return 2
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $server
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status}"
exit 1
esac
exit $RETVAL
---

Robin Haswell

unread,
Mar 28, 2006, 7:22:04 AM3/28/06
to turbo...@googlegroups.com
Matthew Bevan wrote:
> And not storing the actual PID of the running server so it can be
> killed later.

Debian's start-stop-daemon has an option for this. My init script for a
sitechecker I wrote, which identical to CherryPY in terms of IO and
functionality is pasted below. Maybe these are Debian-only
modifications, I dunno, but you can get their source and compile it :-)

Based on the sample Debian initscript.


rob@backux:~$ cat /etc/init.d/sitechecker
#! /bin/sh
#
# Author: Robin Haswell <r...@bronco.co.uk>.
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
#

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Site checker"
NAME=sitechecker
DAEMON=/usr/local/bin/$NAME
PIDFILE=/var/run/$NAME.pid

SCRIPTNAME=/etc/init.d/$NAME

# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

# Read config file if it is present.
#if [ -r /etc/default/$NAME ]
#then
# . /etc/default/$NAME
#fi

#
# Function that starts the daemon/service.
#
d_start() {
start-stop-daemon --start --pidfile $PIDFILE \
--make-pidfile --background --startas $DAEMON
}

#
# Function that stops the daemon/service.
#
d_stop() {
start-stop-daemon --stop --pidfile $PIDFILE
}

#
# Function that sends a SIGHUP to the daemon/service.
#
d_reload() {
start-stop-daemon --stop --pidfile $PIDFILE \
--name $NAME --signal 1
}

case "$1" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
#reload)
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
# If the daemon responds to changes in its config file
# directly anyway, make this an "exit 0".
#
# echo -n "Reloading $DESC configuration..."
# d_reload
# echo "done."
#;;
restart|force-reload)
#
# If the "reload" option is implemented, move the
"force-reload"
# option to the "reload" entry above. If not,
"force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
# echo "Usage: $SCRIPTNAME
{start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

hans

unread,
Mar 28, 2006, 10:22:52 AM3/28/06
to TurboGears
Guys, this is great. Thanks so much. Going to try some of this and
report back. Again, many thanks.

hans

unread,
Mar 28, 2006, 11:57:52 AM3/28/06
to TurboGears
ok! You guys have been a great help. Here is what is working at
http://www.jordanriverdev.com : init.d script below, calling daemonize,
calling cherrypy start script:
#!/bin/sh

# Comments to support chkconfig on RedHat Linux
# chkconfig: 35 96 96

# description: Cherrypy/turbogears start/stop script
# Source: Rune Hansen on
#
http://groups.google.com/group/turbogears/browse_thread/thread/af07ba5360a28a95/73dd5193802b8f70
# Authors: Rune Hansen, $Author: handerson $
# $Id: jrdweb 321 2006-03-28 18:38:46Z handerson $

. /etc/init.d/functions

python=/usr/bin/python
server=daemonize.py
serverdir=/var/www/jrd_marketing_web
serverpidfile=$serverdir/jrdweb.pid
serverlog=$serverdir/jrdlog.log

[ -x $python ] || exit 0

RETVAL=0

start () {
echo "Starting $server: "
if test -f $serverdir/$server
then
cd $serverdir

$serverdir/$server -p $serverpidfile
"$serverdir/jrd_marketing_web-start.py"
echo $serverdir/$server -p $serverpidfile
"$serverdir/jrd_marketing_web-start.py"
RETVAL=$?
echo "\$RETVAL=$RETVAL"

}

}

}

}


THANK YOU.

Jorge Godoy

unread,
Mar 28, 2006, 6:07:41 PM3/28/06
to turbo...@googlegroups.com
"hans" <ha...@hvanderson.com> writes:

> I have blown untold hours trying to find a statement of best practice
> for actually running cherrypy in a production installation to NO avail
> (unless you want the httpd mod_rewrite, which I don't).

(...)

I've written an initscript a long time ago and I've updated it today, after
reading this discussion.

You can find it in http://trac.turbogears.org/turbogears/ticket/172

Download
http://trac.turbogears.org/turbogears/attachment/ticket/172/lsb-initscript.project
and copy it to /etc/init.d/<project> and also make a symlink into
(/usr)/sbin/rc<project>. This way you can use "chkconfig <project>" (or
whatever tool you use to add it to start automatically at a specific
runlevel) or "rc<project> {start|stop|status|restart}" as well.

The changes you need to do are all at the beginning of the file. Changing the
few variables there and the starting comment should be all you need to have it
documented and working.

Assumptions:

- you'll be running in production mode
- your system is LSB-compliant

Here are the variables you'll need to change and their "default" value:

TG_PROJECT="project_name"
PIDFILE=/srv/www/my_tg_website/project.pid
TG_PROJECT_BIN=/srv/www/my_tg_website/start-project.py
TG_PROJECT_CONFIG=/srv/www/my_tg_website/prod.cfg


Where:

TG_PROJECT -> Your project name. It can be anything and will be
echoed at all operations. It is just an informative
text.

PIDFILE -> Where your program's PID will be stored (the initscript
will create this file for you)

TG_PROJECT_BIN -> Your "start-<project>.py" file

TG_PROJECT_CONFIG -> Your "prod.cfg" file


I hope it helps everybody... :-)

--
Jorge Godoy <jgo...@gmail.com>

Reply all
Reply to author
Forward
0 new messages