root/trunk/bin/mongrel_rails

Revision 1003, 10.0 kB (checked in by ezmobius, 1 year ago)

Make mongrel_rails drop the PID file *before* loading the rails framework... helps monit not freak out

Line 
1 # Copyright (c) 2005 Zed A. Shaw
2 # You can redistribute it and/or modify it under the same terms as Ruby.
3 #
4 # Additional work donated by contributors.  See http://mongrel.rubyforge.org/attributions.html
5 # for more information.
6
7 require 'yaml'
8 require 'etc'
9
10 $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
11 require 'mongrel'
12 require 'mongrel/rails'
13
14 Mongrel::Gems.require 'gem_plugin'
15
16 # require 'ruby-debug'
17 # Debugger.start
18
19 module Mongrel
20   class Start < GemPlugin::Plugin "/commands"
21     include Mongrel::Command::Base
22
23     def configure
24       options [
25         ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
26         ["-d", "--daemonize", "Run daemonized in the background", :@daemon, false],
27         ['-p', '--port PORT', "Which port to bind to", :@port, 3000],
28         ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
29         ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
30         ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
31         ['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_processors, 1024],
32         ['-o', '--timeout TIME', "Time to wait (in seconds) before killing a stalled thread", :@timeout, 60],
33         ['-t', '--throttle TIME', "Time to pause (in hundredths of a second) between accepting clients", :@throttle, 0],
34         ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
35         ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
36         ['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
37         ['-B', '--debug', "Enable debugging mode", :@debug, false],
38         ['-C', '--config PATH', "Use a config file", :@config_file, nil],
39         ['-S', '--script PATH', "Load the given file as an extra config script", :@config_script, nil],
40         ['-G', '--generate PATH', "Generate a config file for use with -C", :@generate, nil],
41         ['', '--user USER', "User to run as", :@user, nil],
42         ['', '--group GROUP', "Group to run as", :@group, nil],
43         ['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil]
44       ]
45     end
46
47     def validate
48       if @config_file
49         valid_exists?(@config_file, "Config file not there: #@config_file")
50         return false unless @valid
51         @config_file = File.expand_path(@config_file)
52         load_config
53         return false unless @valid
54       end
55
56       @cwd = File.expand_path(@cwd)
57       valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
58
59       # Change there to start, then we'll have to come back after daemonize
60       Dir.chdir(@cwd)
61
62       valid?(@prefix[0] == ?/ && @prefix[-1] != ?/, "Prefix must begin with / and not end in /") if @prefix
63       valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file"
64       valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file"
65       valid_dir? @docroot, "Path to docroot not valid: #@docroot"
66       valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
67       valid_exists? @config_file, "Config file not there: #@config_file" if @config_file
68       valid_dir? File.dirname(@generate), "Problem accessing directory to #@generate" if @generate
69       valid_user? @user if @user
70       valid_group? @group if @group
71
72       return @valid
73     end
74
75     def run
76       if @generate
77         @generate = File.expand_path(@generate)
78         Mongrel.log(:error, "** Writing config to \"#@generate\".")
79         open(@generate, "w") {|f| f.write(settings.to_yaml) }
80         Mongrel.log(:error, "** Finished.  Run \"mongrel_rails start -C #@generate\" to use the config file.")
81         exit 0
82       end
83
84       config = Mongrel::Rails::RailsConfigurator.new(settings) do
85         if defaults[:daemon]
86           if File.exist? defaults[:pid_file]
87             Mongrel.log(:error, "!!! PID file #{defaults[:pid_file]} already exists.  Mongrel could be running already.  Check your #{defaults[:log_file]} for errors.")
88             Mongrel.log(:error, "!!! Exiting with error.  You must stop mongrel and clear the .pid before I'll attempt a start.")
89             exit 1
90           end
91
92           daemonize
93           write_pid_file
94           Mongrel.log("Daemonized, any open files are closed.  Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info.")
95           Mongrel.log("Settings loaded from #{@config_file} (they override command line).") if @config_file
96         end
97
98         Mongrel.log("Starting Mongrel listening at #{defaults[:host]}:#{defaults[:port]}, further information can be found in log/mongrel-#{defaults[:host]}-#{defaults[:port]}.log")
99
100         listener do
101           mime = {}
102           if defaults[:mime_map]
103             Mongrel.log("Loading additional MIME types from #{defaults[:mime_map]}")
104             mime = load_mime_map(defaults[:mime_map], mime)
105           end
106
107           if defaults[:debug]
108             Mongrel.log("Installing debugging prefixed filters. Look in log/mongrel_debug for the files.")
109             debug "/"
110           end
111
112           Mongrel.log("Starting Rails with #{defaults[:environment]} environment...")
113           Mongrel.log("Mounting Rails at #{defaults[:prefix]}...") if defaults[:prefix]
114           uri defaults[:prefix] || "/", :handler => rails(:mime => mime, :prefix => defaults[:prefix])
115           Mongrel.log("Rails loaded.")
116
117           Mongrel.log("Loading any Rails specific GemPlugins" )
118           load_plugins
119
120           if defaults[:config_script]
121             Mongrel.log("Loading #{defaults[:config_script]} external config script")
122             run_config(defaults[:config_script])
123           end
124
125           setup_rails_signals
126         end
127       end
128
129       config.run
130       Mongrel.log("Mongrel #{Mongrel::Const::MONGREL_VERSION} available at #{@address}:#{@port}")
131
132       unless config.defaults[:daemon]
133         Mongrel.log("Use CTRL-C to stop.")
134       end
135
136       config.join
137
138       if config.needs_restart
139         unless RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/
140           cmd = "ruby #{__FILE__} start #{original_args.join(' ')}"
141           Mongrel.log("Restarting with arguments:  #{cmd}")
142           config.stop(false, true)
143           config.remove_pid_file
144
145           if config.defaults[:daemon]
146             system cmd
147           else
148             Mongrel.log(:error, "Can't restart unless in daemon mode.")
149             exit 1
150           end
151         else
152           Mongrel.log("Win32 does not support restarts. Exiting.")
153         end
154       end
155     end
156
157     def load_config
158       settings = {}
159       begin
160         settings = YAML.load_file(@config_file)
161       ensure
162         Mongrel.log(:error, "** Loading settings from #{@config_file} (they override command line).") unless @daemon || settings[:daemon]
163       end
164
165       settings[:includes] ||= ["mongrel"]
166
167       # Config file settings will override command line settings
168       settings.each do |key, value|
169         key = key.to_s
170         if config_keys.include?(key)
171           key = 'address' if key == 'host'
172           key = 'num_processors' if key == 'num_procs'
173           self.instance_variable_set("@#{key}", value)
174         else
175           failure "Unknown configuration setting: #{key}" 
176           @valid = false
177         end
178       end
179     end
180
181     def config_keys
182       @config_keys ||=
183         %w(address host port cwd log_file pid_file environment docroot mime_map daemon debug includes config_script num_processors num_procs timeout throttle user group prefix)
184     end
185
186     def settings
187       config_keys.inject({}) do |hash, key|
188         value = self.instance_variable_get("@#{key}")
189         key = 'host' if key == 'address'
190         key = 'num_processors' if key == 'num_procs'
191         hash[key.to_sym] ||= value
192         hash
193       end
194     end
195   end
196
197   def Mongrel::send_signal(signal, pid_file)
198     pid = open(pid_file).read.to_i
199     print "Sending #{signal} to Mongrel at PID #{pid}..."
200     begin
201       Process.kill(signal, pid)
202     rescue Errno::ESRCH
203       puts "Process does not exist.  Not running."
204     end
205
206     puts "Done."
207   end
208
209
210   class Stop < GemPlugin::Plugin "/commands"
211     include Mongrel::Command::Base
212
213     def configure
214       options [
215         ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
216         ['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
217         ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
218         ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"]
219       ]
220     end
221
222     def validate
223       @cwd = File.expand_path(@cwd)
224       valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
225
226       Dir.chdir @cwd
227
228       valid_exists? @pid_file, "PID file #@pid_file does not exist.  Not running?"
229       return @valid
230     end
231
232     def run
233       if @force
234         @wait.to_i.times do |waiting|
235           exit(0) if not File.exist? @pid_file
236           sleep 1
237         end
238
239         Mongrel::send_signal("KILL", @pid_file) if File.exist? @pid_file
240       else
241         Mongrel::send_signal("TERM", @pid_file)
242       end
243     end
244   end
245
246
247   class Restart < GemPlugin::Plugin "/commands"
248     include Mongrel::Command::Base
249
250     def configure
251       options [
252         ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, '.'],
253         ['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false],
254         ['-P', '--pid FILE', "Where the PID file is located", :@pid_file, "log/mongrel.pid"]
255       ]
256     end
257
258     def validate
259       @cwd = File.expand_path(@cwd)
260       valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
261
262       Dir.chdir @cwd
263
264       valid_exists? @pid_file, "PID file #@pid_file does not exist.  Not running?"
265       return @valid
266     end
267
268     def run
269       if @soft
270         Mongrel::send_signal("HUP", @pid_file)
271       else
272         Mongrel::send_signal("USR2", @pid_file)
273       end
274     end
275   end
276 end
277
278
279 GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE
280
281
282 if not Mongrel::Command::Registry.instance.run ARGV
283   exit 1
284 end
Note: See TracBrowser for help on using the browser.