割合最近マルチスレッドかつそこそこ高速に、簡単なHTTPリクエストをDBを引いて捌くサーバプログラムを書く機会がありました。
そういうのにMerbをとかを使うのもヘビーウェイトだなあと思い、Ramazeとかもいんじゃないかなあと少し思いましたが折角なのでRack+Sequelでいってみることにしました。 RackについてはMerbでおおよそ知っていましたのでさっくり作ることができたのですが、デーモンの起動スクリプトを作るところで少し困ってしまいました。
Rackは出来合いのrackupというコマンドがあり、これでサーバを起動します。-dオプションを付けるとデーモンとしてバックグラウンド起動するのですが、たいへん不便なことに停止するコマンドがありません。なのでとめる時はpidをもとにSIGINTをおくってやらないといけないです。
また、rackupには実行ユーザーを指定する方法がありません。したがって、rackupコマンドを実行する際にsu -cを利用して、実際の実行ユーザーでデーモンを起動する必要があります。
これらにより以下のようなスクリプトを書きました。出来あがったプログラムはRubyとは思えない速さでウルトラ高速に動作して大変よかったですので機会を見つけてまた使ってみようと思います。
#!/bin/bash
#
# chkconfig: - 85 15
# description: launch rackup app
#
APP_DIR=/home/rackapp/app/rackapp
APP_NAME=rackapp
USER=rackapp
GROUP=rackapp
PORT=9100
ENV=deployment
PID_FILE=/tmp/rackapp.pid
LIBDIR="$APP_DIR/lib"
BOOTUP_RU="$LIBDIR/bootup.ru"
RETVAL=0
# Gracefully exit if the rackup is missing.
which rackup >/dev/null || exit 0
# Go no further if config directory is missing.
[ -d "$APP_DIR" ] || exit 0
function start
{
ARGS="$BOOTUP_RU -s mongrel -p $PORT -E $ENV -D -I $LIBDIR -P $PID_FILE"
echo $ARGS
su -c "rackup $ARGS" $USER
RETVAL=$?
sleep 3
if pgrep -f 'rackup'
then
echo "$APP_NAME listened at $PORT"
else
echo "error: $APP_NAME bootup was failed."
fi
}
function stop
{
if [ -f $PID_FILE ];
then
# send interupt.
kill -INT `cat $PID_FILE`
RETVAL=$?
sleep 3
if pgrep -f 'rackup'
then
echo "error: $APP_NAME was not terminated."
else
# rm $PID_FILE
echo "$APP_NAME was terminated"
fi
else
echo "pid file for $APP_DIR was not found : [$PID_FILE]"
exit 0
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $APP_NAME {start|stop|restart}"
exit 1
;;
esac
exit $RETVAL