Class: Mongrel::Configurator
- Inherits:
-
Object
- Object
- Mongrel::Configurator
- Defined in:
- lib/mongrel/configurator.rb
Overview
Implements a simple DSL for configuring a Mongrel server for your purposes. More used by framework implementers to setup Mongrel how they like, but could be used by regular folks to add more things to an existing mongrel configuration.
It is used like this:
require 'mongrel'
config = Mongrel::Configurator.new :host => "127.0.0.1" do
listener :port => 3000 do
uri "/app", :handler => Mongrel::DirHandler.new(".", load_mime_map("mime.yaml"))
end
run
end
This will setup a simple DirHandler at the current directory and load additional mime types from mimy.yaml. The :host => “127.0.0.1” is actually not specific to the servers but just a hash of default parameters that all server or uri calls receive.
When you are inside the block after Mongrel::Configurator.new you can simply call functions that are part of Configurator (like server, uri, daemonize, etc) without having to refer to anything else. You can also call these functions on the resulting object directly for additional configuration.
A major thing about Configurator is that it actually lets you configure multiple listeners for any hosts and ports you want. These are kept in a map config.listeners so you can get to them.
-
:pid_file => Where to write the process ID.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#defaults ⇒ Object
readonly
Returns the value of attribute defaults.
-
#listeners ⇒ Object
readonly
Returns the value of attribute listeners.
-
#needs_restart ⇒ Object
readonly
Returns the value of attribute needs_restart.
Instance Method Summary collapse
-
#change_privilege(user, group) ⇒ Object
Change privileges of the process to specified user and group.
-
#cloaker(&block) ⇒ Object
Do not call this.
-
#cloaking_class ⇒ Object
Generates a class for cloaking the current self and making the DSL nicer.
-
#daemonize(options = {}) ⇒ Object
Daemonizes the current Ruby script turning all the listeners into an actual “server” or detached process.
-
#debug(location, what = [:access, :files, :objects, :threads, :rails]) ⇒ Object
Calling this before you register your URIs to the given location will setup a set of handlers that log open files, objects, and the parameters for each request.
-
#initialize(defaults = {}, &block) ⇒ Configurator
constructor
You pass in initial defaults and then a block to continue configuring.
-
#join ⇒ Object
This method should actually be called outside of the Configurator block so that you can control it.
-
#listener(options = {}, &block) ⇒ Object
Starts a listener block.
-
#load_mime_map(file, mime = {}) ⇒ Object
Loads the MIME map file and checks that it is correct on loading.
-
#load_plugins(options = {}) ⇒ Object
Uses the GemPlugin system to easily load plugins based on their gem dependencies.
-
#load_yaml(file, default = {}) ⇒ Object
Easy way to load a YAML file and apply default settings.
-
#log(msg) ⇒ Object
Logs a simple message to STDERR (or the mongrel log if in daemon mode).
-
#plugin(name, options = {}) ⇒ Object
Loads and creates a plugin for you based on the given name and configured with the selected options.
-
#redirect(from, pattern, replacement = nil, &block) ⇒ Object
Lets you do redirects easily as described in Mongrel::RedirectHandler.
- #remove_pid_file ⇒ Object
-
#resolve_defaults(options) ⇒ Object
This will resolve the given options against the defaults.
-
#run ⇒ Object
Works like a meta run method which goes through all the configured listeners.
-
#run_config(script) ⇒ Object
Used to allow you to let users specify their own configurations inside your Configurator setup.
-
#setup_signals(options = {}) ⇒ Object
Sets up the standard signal handlers that are used on most Ruby It only configures if the platform is not win32 and doesn’t do a HUP signal since this is typically framework specific.
-
#stop(needs_restart = false, synchronous = false) ⇒ Object
Calls .stop on all the configured listeners so they stop processing requests (gracefully).
-
#uri(location, options = {}) ⇒ Object
Called inside a Configurator.listener block in order to add URI->handler mappings for that listener.
-
#write_pid_file ⇒ Object
Writes the PID file if we’re not on Windows.
Constructor Details
#initialize(defaults = {}, &block) ⇒ Configurator
You pass in initial defaults and then a block to continue configuring.
41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/mongrel/configurator.rb', line 41 def initialize(defaults={}, &block) @listener = nil @listener_name = nil @listeners = {} @defaults = defaults @needs_restart = false @pid_file = defaults[:pid_file] if block cloaker(&block).bind(self).call end end |
Instance Attribute Details
#defaults ⇒ Object (readonly)
Returns the value of attribute defaults.
37 38 39 |
# File 'lib/mongrel/configurator.rb', line 37 def defaults @defaults end |
#listeners ⇒ Object (readonly)
Returns the value of attribute listeners.
36 37 38 |
# File 'lib/mongrel/configurator.rb', line 36 def listeners @listeners end |
#needs_restart ⇒ Object (readonly)
Returns the value of attribute needs_restart.
38 39 40 |
# File 'lib/mongrel/configurator.rb', line 38 def needs_restart @needs_restart end |
Instance Method Details
#change_privilege(user, group) ⇒ Object
Change privileges of the process to specified user and group.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/mongrel/configurator.rb', line 55 def change_privilege(user, group) begin uid, gid = Process.euid, Process.egid target_uid = Etc.getpwnam(user).uid if user target_gid = Etc.getgrnam(group).gid if group if uid != target_uid or gid != target_gid log "Initiating groups for #{user.inspect}:#{group.inspect}." Process.initgroups(user, target_gid) log "Changing group to #{group.inspect}." Process::GID.change_privilege(target_gid) log "Changing user to #{user.inspect}." Process::UID.change_privilege(target_uid) end rescue Errno::EPERM => e log "Couldn't change user and group to #{user.inspect}:#{group.inspect}: #{e.to_s}." log "Mongrel failed to start." exit 1 end end |
#cloaker(&block) ⇒ Object
Do not call this. You were warned.
102 103 104 105 106 107 108 109 |
# File 'lib/mongrel/configurator.rb', line 102 def cloaker(&block) cloaking_class.class_eval do define_method :cloaker_, &block meth = instance_method( :cloaker_ ) remove_method :cloaker_ meth end end |
#cloaking_class ⇒ Object
Generates a class for cloaking the current self and making the DSL nicer.
95 96 97 98 99 |
# File 'lib/mongrel/configurator.rb', line 95 def cloaking_class class << self self end end |
#daemonize(options = {}) ⇒ Object
Daemonizes the current Ruby script turning all the listeners into an actual “server” or detached process. You must call this before frameworks that open files as otherwise the files will be closed by this function.
Does not work for Win32 systems (the call is silently ignored).
Requires the following options or defaults:
-
:cwd => Directory to change to.
-
:log_file => Where to write STDOUT and STDERR.
It is safe to call this on win32 as it will only require the daemons gem/library if NOT win32.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/mongrel/configurator.rb', line 185 def daemonize(={}) ops = resolve_defaults() # save this for later since daemonize will hose it if RUBY_PLATFORM !~ /mswin/ require 'daemons/daemonize' logfile = ops[:log_file] if logfile[0].chr != "/" logfile = File.join(ops[:cwd],logfile) if not File.exist?(File.dirname(logfile)) log "!!! Log file directory not found at full path #{File.dirname(logfile)}. Update your configuration to use a full path." exit 1 end end Daemonize.daemonize(logfile) # change back to the original starting directory Dir.chdir(ops[:cwd]) else log "WARNING: Win32 does not support daemon mode." end end |
#debug(location, what = [:access, :files, :objects, :threads, :rails]) ⇒ Object
Calling this before you register your URIs to the given location will setup a set of handlers that log open files, objects, and the parameters for each request. This helps you track common problems found in Rails applications that are either slow or become unresponsive after a little while.
You can pass an extra parameter what to indicate what you want to debug. For example, if you just want to dump rails stuff then do:
debug "/", what = [:rails]
And it will only produce the log/mongrel_debug/rails.log file. Available options are: :access, :files, :objects, :threads, :rails
NOTE: Use [:files] to get accesses dumped to stderr like with WEBrick.
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/mongrel/configurator.rb', line 322 def debug(location, what = [:access, :files, :objects, :threads, :rails]) require 'mongrel/debug' handlers = { :access => "/handlers/requestlog::access", :files => "/handlers/requestlog::files", :objects => "/handlers/requestlog::objects", :threads => "/handlers/requestlog::threads", :rails => "/handlers/requestlog::params" } # turn on the debugging infrastructure, and ObjectTracker is a pig MongrelDbg.configure # now we roll through each requested debug type, turn it on and load that plugin what.each do |type| MongrelDbg.begin_trace type uri location, :handler => plugin(handlers[type]) end end |
#join ⇒ Object
This method should actually be called outside of the Configurator block so that you can control it. In other words do it like: config.join.
302 303 304 |
# File 'lib/mongrel/configurator.rb', line 302 def join @listeners.values.each {|s| s.acceptor.join } end |
#listener(options = {}, &block) ⇒ Object
Starts a listener block. This is the only one that actually takes a block and then you make Configurator.uri calls in order to setup your URIs and handlers. If you write your Handlers as GemPlugins then you can use load_plugins and plugin to load them.
It expects the following options (or defaults):
-
:host => Host name to bind.
-
:port => Port to bind.
-
:num_processors => The maximum number of concurrent threads allowed.
-
:throttle => Time to pause (in hundredths of a second) between accepting clients.
-
:timeout => Time to wait (in seconds) before killing a stalled thread.
-
:user => User to change to, must have :group as well.
-
:group => Group to change to, must have :user as well.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/mongrel/configurator.rb', line 132 def listener(={},&block) raise "Cannot call listener inside another listener block." if (@listener or @listener_name) ops = resolve_defaults() ops[:num_processors] ||= 950 ops[:throttle] ||= 0 ops[:timeout] ||= 60 @listener = Mongrel::HttpServer.new(ops[:host], ops[:port].to_i, ops[:num_processors].to_i, ops[:throttle].to_i, ops[:timeout].to_i) @listener_name = "#{ops[:host]}:#{ops[:port]}" @listeners[@listener_name] = @listener if ops[:user] and ops[:group] change_privilege(ops[:user], ops[:group]) end # Does the actual cloaking operation to give the new implicit self. if block cloaker(&block).bind(self).call end # all done processing this listener setup, reset implicit variables @listener = nil @listener_name = nil end |
#load_mime_map(file, mime = {}) ⇒ Object
Loads the MIME map file and checks that it is correct on loading. This is commonly passed to Mongrel::DirHandler or any framework handler that uses DirHandler to serve files. You can also include a set of default MIME types as additional settings. See Mongrel::DirHandler for how the MIME types map is organized.
247 248 249 250 251 252 253 254 255 |
# File 'lib/mongrel/configurator.rb', line 247 def load_mime_map(file, mime={}) # configure any requested mime map mime = load_yaml(file, mime) # check all the mime types to make sure they are the right format mime.each {|k,v| log "WARNING: MIME type #{k} must start with '.'" if k.index(".") != 0 } return mime end |
#load_plugins(options = {}) ⇒ Object
Uses the GemPlugin system to easily load plugins based on their gem dependencies. You pass in either an :includes => [] or :excludes => [] setting listing the names of plugins to include or exclude from the determining the dependencies.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/mongrel/configurator.rb', line 215 def load_plugins(={}) ops = resolve_defaults() load_settings = {} if ops[:includes] ops[:includes].each do |plugin| load_settings[plugin] = GemPlugin::INCLUDE end end if ops[:excludes] ops[:excludes].each do |plugin| load_settings[plugin] = GemPlugin::EXCLUDE end end GemPlugin::Manager.instance.load(load_settings) end |
#load_yaml(file, default = {}) ⇒ Object
Easy way to load a YAML file and apply default settings.
236 237 238 |
# File 'lib/mongrel/configurator.rb', line 236 def load_yaml(file, default={}) default.merge(YAML.load_file(file)) end |
#log(msg) ⇒ Object
Logs a simple message to STDERR (or the mongrel log if in daemon mode).
387 388 389 |
# File 'lib/mongrel/configurator.rb', line 387 def log(msg) STDERR.print "** ", msg, "\n" end |
#plugin(name, options = {}) ⇒ Object
Loads and creates a plugin for you based on the given name and configured with the selected options. The options are merged with the defaults prior to passing them in.
261 262 263 264 |
# File 'lib/mongrel/configurator.rb', line 261 def plugin(name, ={}) ops = resolve_defaults() GemPlugin::Manager.instance.create(name, ops) end |
#redirect(from, pattern, replacement = nil, &block) ⇒ Object
Lets you do redirects easily as described in Mongrel::RedirectHandler. You use it inside the configurator like this:
redirect("/test", "/to/there") # simple
redirect("/to", /t/, 'w') # regexp
redirect("/hey", /(w+)/) {|match| ...} # block
273 274 275 |
# File 'lib/mongrel/configurator.rb', line 273 def redirect(from, pattern, replacement = nil, &block) uri from, :handler => Mongrel::RedirectHandler.new(pattern, replacement, &block) end |
#remove_pid_file ⇒ Object
78 79 80 |
# File 'lib/mongrel/configurator.rb', line 78 def remove_pid_file File.unlink(@pid_file) if @pid_file and File.exists?(@pid_file) end |
#resolve_defaults(options) ⇒ Object
This will resolve the given options against the defaults. Normally just used internally.
113 114 115 |
# File 'lib/mongrel/configurator.rb', line 113 def resolve_defaults() .merge(@defaults) end |
#run ⇒ Object
Works like a meta run method which goes through all the configured listeners. Use the Configurator.join method to prevent Ruby from exiting until each one is done.
280 281 282 283 284 285 286 |
# File 'lib/mongrel/configurator.rb', line 280 def run @listeners.each {|name,s| s.run } $mongrel_sleeper_thread = Thread.new { loop { sleep 1 } } end |
#run_config(script) ⇒ Object
Used to allow you to let users specify their own configurations inside your Configurator setup. You pass it a script name and it reads it in and does an eval on the contents passing in the right binding so they can put their own Configurator statements.
346 347 348 349 350 351 352 |
# File 'lib/mongrel/configurator.rb', line 346 def run_config(script) if binding.respond_to?(:eval) binding.eval(File.read(script)) else open(script) {|f| eval(f.read, proc {self}) } end end |
#setup_signals(options = {}) ⇒ Object
Sets up the standard signal handlers that are used on most Ruby It only configures if the platform is not win32 and doesn’t do a HUP signal since this is typically framework specific.
Requires a :pid_file option given to Configurator.new to indicate a file to delete.
It sets the MongrelConfig.needs_restart attribute if the start command should reload. It’s up to you to detect this and do whatever is needed for a “restart”.
This command is safely ignored if the platform is win32 (with a warning)
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/mongrel/configurator.rb', line 364 def setup_signals(={}) ops = resolve_defaults() # forced shutdown, even if previously restarted (actually just like TERM but for CTRL-C) trap("INT") { log "INT signal received."; stop(false) } # clean up the pid file always at_exit { remove_pid_file } if RUBY_PLATFORM !~ /mswin/ # graceful shutdown trap("TERM") { log "TERM signal received."; stop } trap("USR1") { log "USR1 received, toggling $mongrel_debug_client to #{!$mongrel_debug_client}"; $mongrel_debug_client = !$mongrel_debug_client } # restart trap("USR2") { log "USR2 signal received."; stop(true) } log "Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart)." else log "Signals ready. INT => stop (no restart)." end end |
#stop(needs_restart = false, synchronous = false) ⇒ Object
Calls .stop on all the configured listeners so they stop processing requests (gracefully). By default it assumes that you don’t want to restart.
291 292 293 294 295 296 |
# File 'lib/mongrel/configurator.rb', line 291 def stop(needs_restart=false, synchronous=false) @listeners.each do |name,s| s.stop(synchronous) end @needs_restart = needs_restart end |
#uri(location, options = {}) ⇒ Object
Called inside a Configurator.listener block in order to add URI->handler mappings for that listener. Use this as many times as you like. It expects the following options or defaults:
-
:handler => HttpHandler – Handler to use for this location.
-
:in_front => true/false – Rather than appending, it prepends this handler.
165 166 167 168 |
# File 'lib/mongrel/configurator.rb', line 165 def uri(location, ={}) ops = resolve_defaults() @listener.register(location, ops[:handler], ops[:in_front]) end |
#write_pid_file ⇒ Object
Writes the PID file if we’re not on Windows.
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/mongrel/configurator.rb', line 83 def write_pid_file if RUBY_PLATFORM !~ /mswin/ log "Writing PID file to #{@pid_file}" open(@pid_file,"w") {|f| f.write(Process.pid) } open(@pid_file,"w") do |f| f.write(Process.pid) File.chmod(0644, @pid_file) end end end |