Rails環境を持った状態でdaemon化する方法

ひとまずログとして.参考にしたのは,http://snippets.dzone.com/posts/show/2265です.基本部分はそのまま,必要な部分だけ書き換えました.

# Post-process of MessageSender
require 'optparse'
require 'fileutils'

module TinyDaemon
  # Default options
  OPTIONS = {
    :log_file     => "#{name}.log",
    :pid_dir      => "./",
    :pid_file     => "#{name}.pid",
  }

  class Base
    def self.daemonize(command, options ={})
      OPTIONS[:after_status] = options[:after_status] unless options[:after_status].nil?

      Controller.daemonize(self, command)
    end

    def self.pidfile
      File.join(OPTIONS[:pid_dir], OPTIONS[:pid_file])
    end
  end

  class PidFile
    def self.setpid(daemon, pid)
      File.open(daemon.pidfile, 'w') do |file|
        file << pid
      end
    end

    def self.getpid(daemon)
      IO.read(daemon.pidfile).to_i rescue nil
    end
  end

  module Controller
    def self.daemonize(daemon, command)
      case command
      when 'start'
        puts "Starting daemons...."
        start(daemon)
      when 'stop'
        puts "Stopping daemons...."
        stop(daemon)
      when 'restart'
        puts "Restarting daemons...."
        stop(daemon)
        start(daemon)
      when 'status'
        puts "STATUS"
      else
        puts "Usage: #{File.basename($0)} (start|stop|restart|status)"
        exit
      end
    end

    def self.start(daemon)
      fork do
        Process.setsid
        exit if fork
        PidFile.setpid(daemon, Process.pid)
        Dir.chdir(OPTIONS[:pid_dir])
        File.umask 0000

        STDIN.reopen "/dev/null"
        STDOUT.reopen "/dev/null", "a"
        STDERR.reopen STDOUT

        Signal.trap(:TERM) do
          daemon.stop
          exit
        end
        Signal.trap(:HUP) do
          daemon.stop
          daemon.start
        end
        Signal.trap(:INT) do
          daemon.stop
          exit
        end

        daemon.start
      end
    end

    def self.stop(daemon)
      if !File.file?(daemon.pidfile)
        puts "Pid file not found."
        exit
      end
      pid = PidFile.getpid(daemon)
      FileUtils.rm(daemon.pidfile)
      begin
        return pid && Process.kill("TERM", pid)
      rescue => ex
        puts "Daemon process Not found."
      end
    end
  end
end

$command = "start"   if ARGV.include?("start")
$command = "stop"    if ARGV.include?("stop")
$command = "restart" if ARGV.include?("restart")

# parse arguments
ARGV.options do |opts|
  script_name = File.basename($0)
  opts.banner = "Usage: #{script_name} (start|stop|restart)"

  opts.separator ""

  opts.on( "-e", "--environment=name", String,
    "Specifies the enviroment to run this daemon under (test/development/production).",
    "Default: development" ){ |v| $rails_enviroment = v }
  opts.on( "-h", "--help", "Show this help message."){ puts opts; exit }

  opts.parse!

  if $rails_enviroment.nil? or $command.nil?
    puts opts.help
    exit
  end
end

# Environment variables
ENV["RAILS_ENV"] = $rails_enviroment
RAILS_ENV.replace($rails_enviroment) if defined?(RAILS_ENV)

# Load Rails environment
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")

TinyDaemon::OPTIONS[:pid_dir]      = "/var/log"
TinyDaemon::OPTIONS[:pid_file]     = "mydaemon.pid"

class MyDaemon < TinyDaemon::Base
  def self.start_daemon(options)
    self.daemonize("start", TinyDaemon::OPTIONS)
  end

  def self.start
    loop {
      puts "OK"
      sleep 900
    }
  end

  def self.stop_daemon(options)
    self.stop
  end

  def self.stop
    daemonize("stop", TinyDaemon::OPTIONS)
  end
end

MyDaemon .send("#{$command}_daemon", TinyDaemon::OPTIONS) unless $command.nil?

ただこれだとシグナル送るのにPIDを調べないといけない.もうちょっと改良すべきか.

 
comments powered by Disqus