Rubyのdaemonを手軽に作る
今回も基本的には個人的なメモ書き...φ(・ω・`)
時間のかかる処理を非同期化して動かすって手段(gem/plugin等)はいろいろありまして、
そういうのを知らなかった頃、自前でタスク処理フレームワーク*1を組んだりしましたが、
それは置いておいて・・・
そこまでいかなくても、何かを単純な処理を実行しっぱなしにしたい、
つまりdaemon化したいってのは良くある話でして
そんな人のために、Ruby1.9系には「Process.daemon」という、
そのものズバリのメソッドが用意されています
ただ、こいつは「単純なdaemon化*2」しかしません
pidファイルの処理や、出力をlogへリダイレクトなんて処理は、
自前で書かなければなりません(´-ω-)
それも面倒なので、軽量な仕組みはないかな・・・と探したところ、
「daemon-spawn」というgemを見つけました
https://github.com/alexvollmer/daemon-spawn
使い方はREADMEにもありますが、
短いコードなので読んじゃった方が早いかもしれません
以下、Rails3アプリに組み込むことを想定しますが、
例によってGemfileにgemを追加・・・とはいきませんΣ(・ω・ノ)ノ
このgem、名前は「daemon-spawn」なのですが、
requireファイル名は「daemon_spawn」なのです
そこで、こう書きます
gem 'daemon-spawn', :require => 'daemon_spawn'
後はいつものようにbundle installでOKです
続いて、daemon化したい処理を書きます
# coding: utf-8 require File.expand_path(File.dirname(__FILE__) + '/../config/environment') # rails runner前提だとこのrequireいらないかも class MyDaemon < DaemonSpawn::Base def start(args) # argsにはARGVがそのまま渡されてくる puts "start : #{Time.now}" # 何か終わらない処理 end def stop puts "stop : #{Time.now}" # やることがなくても、メソッドを実装しないと例外 end end MyDaemon.spawn!({ :working_dir => Rails.root, # これだけ必須オプション :pid_file => File.expand_path(File.dirname(__FILE__) + '/../tmp/hoge.pid'), :log_file => File.expand_path(File.dirname(__FILE__) + '/../log/hoge.log'), :sync_log => true, :singleton => true # これを指定すると多重起動しない })
DaemonSpawn::Baseを継承したクラスに、
startとstopを実装し、spawn!を呼ぶだけです
startの中身がすぐ終わるものだとdaemonも終了してしまうので、
処理をloopで囲むなりなんなりしてください
(もっとも、これを使おうと思った時点でそれに近い実装だと思いますが)
ここまでやれば、start/stop/restart/statusを渡して起動するだけです
以前、unicorn_railsで引っかかったので、念のためbundle exec経由で
rails runnerでもいけます
$ cd RAILS_ROOT $ bundle exec ruby script/my_daemon start $ rails runner script/my_daemon stop
「:singleton => true」を指定しているので、
cronで数分おきに起動してやれば、生きていれば何もしませんし、
何らかの事情で落ちていればまた復活します(`・ω・´) b *3
基本的にはこれでおしまいなのですが、
本番で動かそうとしてはまったのでもうちょっと
上記の方法では当然ながらdevelopment環境で起動されます
本番でproduction環境を使うならRAILS_ENVを使えばいいのですが、
これを書く位置を間違えると環境が変わりませんΣ(・ω・ノ)ノ
正解はこれです
$ RAILS_ENV=production bundle exec ruby script/my_daemon start
途中や後ろにつけると環境が切り替わらなかったのでご注意を・・・*4