ry / ebb fork watch download tarball
public
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Search Repo:
ebb / ruby_lib / ebb / runner.rb
100644 133 lines (113 sloc) 4.447 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
require 'optparse'
 
module Kernel
  unless respond_to? :daemonize # Already part of Ruby 1.9, yeah!
    # Turns the current script into a daemon process that detaches from the console.
    # It can be shut down with a TERM signal. Taken from ActiveSupport.
    def daemonize
      exit if fork # Parent exits, child continues.
      Process.setsid # Become session leader.
      exit if fork # Zap session leader. See [1].
      Dir.chdir "/" # Release old working directory.
      File.umask 0000 # Ensure sensible umask. Adjust as needed.
      STDIN.reopen "/dev/null" # Free file descriptors and
      STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
      STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
      trap("TERM") { exit }
    end
  end
end
 
module Ebb
  class Runner
    # Classes are modules and I hate this 'Base' class pattern. I'm putting
    # other classes inside this one.
    autoload :Rails, LIBDIR + '/ebb/runner/rails'
    
    # Kill the process which PID is stored in +pid_file+.
    def self.kill(pid_file, timeout=60)
      raise ArgumentError, 'You must specify a pid_file to stop deamonized server' unless pid_file
      
      if pid = File.read(pid_file)
        pid = pid.to_i
        
        Process.kill('KILL', pid)
        Ebb.log.puts "stopped!"
      else
        Ebb.log.puts "Can't stop process, no PID found in #{@pid_file}"
      end
    rescue Errno::ESRCH # No such process
      Ebb.log.puts "process not found!"
    ensure
      File.delete(pid_file) rescue nil
    end
 
    def self.remove_pid_file(file)
      File.delete(file) if file && File.exists?(file) && Process.pid == File.read(file)
    end
 
    def self.write_pid_file(file)
      Ebb.log.puts ">> Writing PID to #{file}"
      open(file,"w+") { |f| f.write(Process.pid) }
      File.chmod(0644, file)
    end
    
    attr_reader :options
    
    def initialize
      @parser = OptionParser.new
      @options = {
        :port => 4001,
        :timeout => 60
      }
    end
    
    def parse_options(argv)
      @parser.banner = "Usage: #{self.class} [options] start | stop"
      @parser.separator ""
      extra_options if respond_to?(:extra_options)
      
      @parser.separator ""
      @parser.on("-p", "--port PORT", "(default: #{@options[:port]})") { |p| @options[:port] = p }
      @parser.on("-s", "--socket SOCKET", "listen on unix domain socket") { |socket| options[:unix_socket] = socket }
      @parser.on("-d", "--daemonize", "Daemonize") { @options[:daemonize] = true }
      @parser.on("-l", "--log-file FILE", "File to redirect output") { |f| @options[:log_file]=f }
      @parser.on("-P", "--pid-file FILE", "File to store PID") { |f| @options[:pid_file]=f }
      # @parser.on("-t", "--timeout SECONDS", "(default: #{@options[:timeout]})") { |s| @options[:timeout]=s }
      
      @parser.separator ""
      @parser.on_tail("-h", "--help", "Show this message") do
        Ebb.log.puts @parser
        exit
      end
      @parser.on_tail('-v', '--version', "Show version") do
        Ebb.log.puts Ebb::Client::BASE_ENV['SERVER_SOFTWARE']
        exit
      end
      
      @parser.parse!(argv)
    end
    
    def run(argv)
      parse_options(argv)
      
      case argv[0]
      when 'start'
        Ebb.log.print("Ebb is loading the application...")
        Ebb.log.flush()
        @app = app(@options)
        Ebb.log.puts("done")
        
        if @options[:daemonize]
          pwd = Dir.pwd # Current directory is changed during daemonization, so store it
          Kernel.daemonize
          Dir.chdir pwd
          trap('HUP', 'IGNORE') # Don't die upon logout
        end
        
        if @options[:log_file]
          [STDOUT, STDERR].each { |f| f.reopen @options[:log_file], 'a' }
        end
        
        if @options[:pid_file]
          Runner.write_pid_file(@options[:pid_file])
          at_exit do
            Ebb.log.puts ">> Exiting!"
            Runner.remove_pid_file(@options[:pid_file])
          end
        end
        
        Ebb::start_server(@app, @options)
      when 'stop'
        Ebb::Runner.kill @options[:pid_file], @options[:timeout]
      when nil
        Ebb.log.puts "Command required"
        Ebb.log.puts @parser
        exit 1
      else
        abort "Invalid command : #{argv[0]}"
      end
      
    end
  end
end