Running catalyst applications under perlbal + starman + psgi

WTF are those?

Why do all that? Why not apache and FastCGI like everyone else?

Setup

Perlbal

LOAD Vpaths# starman webservers
CREATE POOL prod_starman
 POOL prod_starman ADD 127.0.0.1:5000# static webserver
CREATE SERVICE web_static
  SET role                   = web_server
  SET docroot                = /home/myapp/prod/root
  SET dirindexing            = 0
  SET enable_concatenate_get = on
ENABLE web_static# HTTP reverse proxy load balancer
CREATE SERVICE web_prod
 SET role                 = reverse_proxy
 SET pool                 = prod_starman
 SET buffer_uploads       = on
ENABLE web_prod# HTTP selector
CREATE SERVICE myapp_selector
 SET listen              = 0.0.0.0:80
 SET role                = selector
 SET plugins             = vpaths
 VPATH ^/static/.*       = web_static
 VPATH .*                = web_prod
ENABLE myapp_selector
# disallow injection
HEADER myapp_selector REMOVE X-Forwarded-Proto# HTTPS selector
CREATE SERVICE myapp_ssl_selector
 SET listen              = 0.0.0.0:443
 SET role                = selector
 SET plugins             = vpaths
 SET enable_ssl          = on
 SET ssl_key_file        = /etc/certs/myapp.com.key.plain
 SET ssl_cert_file       = /etc/lighttpd/certs/myapp.com.combined.pem
 VPATH ^/static/.*       = web_static
 VPATH .*                = web_prod
ENABLE myapp_ssl_selector
HEADER myapp_ssl_selector INSERT X-Forwarded-Proto: HTTPS# management port, telnet in to chat with perlbal
CREATE SERVICE mgmt
 SET role   = management
 SET listen = 127.0.0.1:60000
ENABLE mgmt

Starman

site-init.sh

#!/bin/bash. /lib/lsb/init-functionsif [ ! $APP ]; then
    echo "\$APP is not defined, please do not call this script directly."
    exit 1
fiexport APPDIR="/home/myapp/$APP"
export PIDDIR=/tmp
export PIDFILE=$PIDDIR/${APP}.pid
export STARMAN="/home/myapp/prod/bin/starman-myapp.sh"if [ ! -d $APPDIR ]; then
    echo "$APPDIR does not exist"
    exit 1
ficheck_running() {
    [ -s $PIDFILE ] && kill -0 $(cat $PIDFILE) >/dev/null 2>&1
}check_compile() {
  if ( cd $APPDIR ; perl -Ilib -M$APPLIB -ce1 ) ; then
    return 1
  else
    return 0
  fi
}_start() {  /sbin/start-stop-daemon --start --pidfile $PIDFILE \
  --chdir $APPDIR --startas $STARMAN  echo ""
  echo "Waiting for $APPNAME to start..."  for i in 1 2 3 4 ; do
    sleep 1
    if check_running ; then
      echo "$APPNAME is now starting up"
      return 0
    fi
  done  # sometimes it takes two tries.
  echo "Failed. Trying again..."
  /sbin/start-stop-daemon --start --pidfile $PIDFILE \
  --chdir $APPDIR --startas $STARMAN  for i in 1 2 3 4 ; do
    sleep 1
    if check_running ; then
      echo "$APPNAME is now starting up"
      return 0
    fi
  done  return 1
}start() {
    log_daemon_msg "Starting $APP" $STARMAN
    echo ""    if check_running; then
        log_progress_msg "already running"
        log_end_msg 0
        exit 0
    fi    rm -f $PIDFILE 2>/dev/null    _start
    log_end_msg $?
    return $?
}stop() {
    log_daemon_msg "Stopping $APP" $STARMAN
    echo ""    /sbin/start-stop-daemon --stop --oknodo --pidfile $PIDFILE
    sleep 3
    log_end_msg $?
    return $?
}restart() {
    log_daemon_msg "Restarting $APP" $STARMAN
    echo ""    if check_compile ; then
        log_failure_msg "Error detected; not restarting."
        log_end_msg 1
        exit 1
    fi    /sbin/start-stop-daemon --stop --oknodo --pidfile $PIDFILE
    _start
    log_end_msg $?
    return $?
}
# See how we were called.
case "$1" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    restart|force-reload)
        restart
    ;;
    *)
        echo $"Usage: $0 {start|stop|restart}"
        exit 1
esac
exit $?

bin/starman-myapp.sh:

#!/bin/bashif [ ! $WORKERS ]; then
    echo "\$WORKERS is not defined"
    exit 1
fiif [ ! $PORT ]; then
    echo "\$PORT is not defined"
    exit 1
fiPSGIAPP="$APPDIR/script/myapp_psgi.psgi"
echo "Starting $PSGIAPP, pidfile $PIDFILE..."
starman -I$APPDIR/lib $PSGIAPP --workers $WORKERS --pid $PIDFILE --port $PORT --daemonize
#!/bin/sh# settings
export APP="prod"
export APPLIB="MyApp"
export WORKERS=5
export PORT=5000# this runs site-init.sh, assuming it's in the same directory
. "$( cd "$( dirname "$0" )" && pwd )/site-init.sh"

PSGI

#!/usr/bin/env perl
use strict;
use warnings;use FindBin;
use lib "$FindBin::Bin/../lib";use MyApp;
use MyApp::Util;use Catalyst::Engine::PSGI;
use FCGI::ProcManager;
use Plack::Builder;
use Plack::Middleware::AccessLog;
use Plack::Middleware::Debug;# I load configuration info from my app. you are probably not cool enough to do this
my $config = MyApp::Util->get_config;
my $name = $config->{server_name} or die "server_name not set in config";
my $log_dir = MyApp::Util->log_dir or die "log_dir not set in config";
die "log_dir $log_dir does not exist\n" unless -d $log_dir;
die "log_dir $log_dir is not writable\n" unless -w $log_dir;MyApp->setup_engine('PSGI');
my $app = sub { MyApp->run(@_) };builder {
    my $logfh;
    my $access_logfile = "$log_dir/access-log-$name";
    my $error_logfile = "$log_dir/error-log-$name";
    open $logfh, ">>", $access_logfile or die $!;
    open STDERR, ">>", $error_logfile or die $!;
    $logfh->autoflush(1);    enable "AccessLog", logger => sub { print $logfh @_ };    # debug panel
    enable 'Debug', panels => $config->{plack_debug_panel}
    if $config->{plack_debug_panel};    # if we're using perlbal, fix some request params. replace 12.34.56.78 with your public IP
    enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1'
                    || $_[0]->{REMOTE_ADDR} eq '12.34.56.78' }
    "Plack::Middleware::ReverseProxy";    return $app;
};