Ruby 2.0 + Sinatra + Thin を Windows サービス化してみた

簡単な Web アプリを Ruby + Sinatra で作って、それを Windows サービス化しようとしたらすごくハマったのでメモしておく。 最終的には Thin を使って Winsw で Windows サービス化した。

リポジトリhttps://github.com/toruuetani/SinatraThinService

Ruby は 2.0 から使い始めたのでほとんど知らない。おかしいところがあれば指摘してください。

前提

Ruby 製 HTTP サーバー

とりあえず検索してみたところ有名なのはこれくらいらしい。

WEBrick は開発向けなので除外するととして、 Passenger と Unicorn は Windows で動かないので問題外。 そうなると Mongrel と Thin しか候補がないんだけども、 Mongrel はすでに開発が止まっているらしい。 実際 Ruby 1.9 には正式に対応しておらず、開発版でなんとか動く状況のようだ。 Ruby 2.0 ではほぼ情報がなく、開発版でも動作しなかったので Thin しか望みがない。

ただし、 Mongrel では mongrel_service というそのものずばりの gem があったんだけども Thin には Windows サービス化する方法がない。

winsw: Windows Service Wrapper

そこで kohsuke/winsw という実行モジュールを Windows サービス化する ユーティリティを使うことにした。 Jenkins でも使われているものなので、信頼性も十分だろう。

ただ困ったことに Bundler のように子プロセスを起動する場合には対応しておらず、サービスを停止しても子プロセスが 停止してくれない。モダンな Ruby 環境であるなら Bundler ははずせないだろう、と思ったのがいろいろハマった原因の一つ。

起動自体は問題ないが、停止できないのは気持ち悪いので少し変更して使うことにした。

Sinatra の準備

ここからは実際に動かす方法を記述していく。

RubyC:\Ruby200 にインストールされているものとして Bundler をインストールしておくこと。

gem install bundler

Bundler をインストールしたら作業ディレクトリで以下のコマンドを実行する。

※ thin の依存ライブラリ eventmachine のコンパイルに必要なので、 DevKit と gcc をインストールしておくこと。

bundle init
#Modify Gemfile
bundle install --path vendor/bundle
# A sample Gemfile
source "https://rubygems.org"

gem "sinatra"
group :development do
    gem "sinatra-contrib"
    gem "better_errors"
    gem "binding_of_caller"
end
gem "thin"

最低限 Sinatra が動くコードを用意する。

# -*- encoding: utf-8 -*-
# app.rb
require "rubygems"
require "sinatra"

get "/" do
    "Hello"
end

bundle exec ruby app.rbhttp://localhost:4567 が動くことを確認する。 または config.ru を用意して bundle exec rackuphttp://localhost:9292 が動くことを確認する。

# -*- encoding: utf-8 -*-
# config.ru
require "./app.rb"


run Sinatra::Application

winsw の準備

現時点での最新(1.13)だと子プロセスを停止できないので、 Bundler 経由だと winsw を停止しても Thin が停止できない。

winsw.exe -> ruby(Bundler) -> ruby(Thin) となるので winsw.exe を停止しても ruby(Bundler) しか停止されない。

なのでパッチを当てたものを使う(上記リポジトリに含まれる SinatraThinService.exe )。

winsw.exe の設定は winsw.xml で行う。名前は任意のものに変更可能。ポイントは次の通り。

  • Bundler で使う Gemfile環境変数 BUNDLE_GEMFILE で指定する。
  • workingdirectory を指定する。
<service>
  <id>SinatraThinService</id>
  <name>SinatraThinService</name>
  <description>Sinatra with Thin Service</description>
  <env name="PATH" value="C:\Ruby200\bin;%PATH%;"/>
  <env name="BUNDLE_GEMFILE" value="C:\Documents\Work\SinatraThinService\Gemfile"/>
  <executable>ruby</executable>
  <arguments>C:\Ruby200\bin\bundle exec ruby .\vendor\bundle\ruby\2.0.0\bin\thin -R .\config.ru start</arguments>
  <workingdirectory>C:\Documents\Work\SinatraThinService</workingdirectory>
  <logmode>rotate</logmode>
</service>

サービスの使い方

管理者権限でコマンドプロンプトを起動し、以下のコマンドを実行する。これで http://localhost:3000 でアクセスできるか確認する。

SinatraThinService install
SinatraThinService start

停止するときは

SinatraThinService stop

アンインストールは次の通り。

SinatraThinService uninstall