デーモンを作る場合の最もシンプルなコードサンプル。
#!/usr/bin/env ruby require "al_worker" class Worker1 < AlWorker end worker1 = Worker1.new() worker1.daemon()
スーパークラス AlWorkerをextendして、そこへ機能を実装します。
コマンドラインから実行すると、すぐ終了したかのように見えますが、プログラムは常駐しています。
内部的な「識別名」を持っており、デフォルトで「al_worker」となります。
$ruby -I . sample1.rb $ps ax | grep ruby 82918 ?? Is 0:00.00 ruby -I . sample1.rb (ruby19) $_
同じ識別名を持ったプログラムの二重起動を阻止しますので、もう一度起動しようとすると、エラーになります。
$ruby -I . sample1.rb ERROR: Still work. $_
/tmp 以下にpidファイルとログファイルが作成されます。この時ファイル名として、識別名 "al_worker"が使われます。
$ ls /tmp al_worker.log al_worker.pid $_
プロセスの終了は、kill シグナル、もしくは後述の -k オプションによって行います。
$ kill `cat /tmp/al_worker.pid` $ps ax | grep ruby $_
AlWorkerのコンストラクタに文字列を渡すことで、任意の識別名をつけることができます。
worker1 = Worker1.new( "ANY_NAME" )
または、
class Worker1 < AlWorker def initialize() super( "ANY_NAME" ) end end
初期化処理にコンストラクタ(initializeメソッド)を使うこともできますが、ログが記録できない、エラー処理が弱いなど、使いにくい面があるので、イニシャライザを用意しました。
initialize2()というメソッドを定義すると、コンストラクタに続いて呼ばれます。
コンストラクタをオーバライドする場合と違い、親をsuperで呼び出す必要はありません。
コンストラクタは常駐前に、イニシャライザは常駐後に呼び出されるという違いがあります。
def initialize2() # any initialize code end
フォアグラウンドで動作し、常駐の必要が無い場合は、daemonメソッドを run メソッドに変更します。
worker1 = Worker1.new() worker1.run()
"識別名.ini" もしくは、"識別名.yaml" というファイルが存在する場合、それを設定ファイルと判断し自動的に読み込みます。
プログラムからは、@config[:key] として参照できます。
設定ファイルは、iniフォーマットもしくは、yamlフォーマットで記述し、どちらのフォーマットかは拡張子で判断します。
HUPシグナルで、設定ファイルを再読込します。
例1
key1=val1 key2=val2
読み込み結果 @config
{:key1=>"val1", :key2=>"val2"}
例2
[section1] key1=val1 key2=val2 [section2] key3=val3 key4=val4
読み込み結果 @config
{:section1=>{:key1=>"val1", :key2=>"val2"}, :section2=>{:key3=>"val3", :key4=>"val4"}}
parse_option() を使うと、よく使われる起動オプションを解析し、動作に反映します。
worker1 = Worker1.new() worker1.parse_option() worker1.daemon()
オプション | 動作 |
---|---|
-p <pidfile> | PIDファイルの指定 |
-l <logfile> | ログファイルの指定 |
-c <conffile> | 設定ファイルの指定 |
-d | デバグモード。daemonにならずフォアグラウンド実行される。 |
-k | 常駐しているプロセスを終了させる。kill `cat /tmp/pidfile` と同等。 |
-r | 常駐しているプロセスを終了し、再度常駐する。 |
Ruby標準ライブラリのOptParseを使ってアプリケーション独自のオプションを解析する場合は、上記のオプションを追加するメソッドが用意してあります。(v3.8以降)
worker1 = Worker1.new() opt = OptionParser.new() worker1.append_default_option_to( opt ) # 独自オプションの追加 opt.on(....) worker1.daemon()