dev: remove isolate dependency
[unicorn.git] / lib / unicorn / configurator.rb
blob9406223b8b9b55464dc7ade686f010a83e789e9c
1 # -*- encoding: binary -*-
2 require 'logger'
3 require 'unicorn/ssl_configurator'
5 # Implements a simple DSL for configuring a \Unicorn server.
7 # See http://unicorn.bogomips.org/examples/unicorn.conf.rb and
8 # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
9 # example configuration files.  An example config file for use with
10 # nginx is also available at
11 # http://unicorn.bogomips.org/examples/nginx.conf
13 # See the link:/TUNING.html document for more information on tuning unicorn.
14 class Unicorn::Configurator
15   include Unicorn
16   include Unicorn::SSLConfigurator
18   # :stopdoc:
19   attr_accessor :set, :config_file, :after_reload
21   # used to stash stuff for deferred processing of cli options in
22   # config.ru after "working_directory" is bound.  Do not rely on
23   # this being around later on...
24   RACKUP = {
25     :daemonize => false,
26     :host => Unicorn::Const::DEFAULT_HOST,
27     :port => Unicorn::Const::DEFAULT_PORT,
28     :set_listener => false,
29     :options => { :listeners => [] }
30   }
32   # Default settings for Unicorn
33   DEFAULTS = {
34     :timeout => 60,
35     :logger => Logger.new($stderr),
36     :worker_processes => 1,
37     :after_fork => lambda { |server, worker|
38         server.logger.info("worker=#{worker.nr} spawned pid=#{$$}")
39       },
40     :before_fork => lambda { |server, worker|
41         server.logger.info("worker=#{worker.nr} spawning...")
42       },
43     :before_exec => lambda { |server|
44         server.logger.info("forked child re-executing...")
45       },
46     :pid => nil,
47     :preload_app => false,
48     :check_client_connection => false,
49     :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
50     :client_body_buffer_size => Unicorn::Const::MAX_BODY,
51     :trust_x_forwarded => true,
52   }
53   #:startdoc:
55   def initialize(defaults = {}) #:nodoc:
56     self.set = Hash.new(:unset)
57     @use_defaults = defaults.delete(:use_defaults)
58     self.config_file = defaults.delete(:config_file)
60     # after_reload is only used by unicorn_rails, unsupported otherwise
61     self.after_reload = defaults.delete(:after_reload)
63     set.merge!(DEFAULTS) if @use_defaults
64     defaults.each { |key, value| self.__send__(key, value) }
65     Hash === set[:listener_opts] or
66         set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
67     Array === set[:listeners] or set[:listeners] = []
68     reload(false)
69   end
71   def reload(merge_defaults = true) #:nodoc:
72     if merge_defaults && @use_defaults
73       set.merge!(DEFAULTS) if @use_defaults
74     end
75     instance_eval(File.read(config_file), config_file) if config_file
77     parse_rackup_file
79     RACKUP[:set_listener] and
80       set[:listeners] << "#{RACKUP[:host]}:#{RACKUP[:port]}"
82     # unicorn_rails creates dirs here after working_directory is bound
83     after_reload.call if after_reload
85     # working_directory binds immediately (easier error checking that way),
86     # now ensure any paths we changed are correctly set.
87     [ :pid, :stderr_path, :stdout_path ].each do |var|
88       String === (path = set[var]) or next
89       path = File.expand_path(path)
90       File.writable?(path) || File.writable?(File.dirname(path)) or \
91             raise ArgumentError, "directory for #{var}=#{path} not writable"
92     end
93   end
95   def commit!(server, options = {}) #:nodoc:
96     skip = options[:skip] || []
97     if ready_pipe = RACKUP.delete(:ready_pipe)
98       server.ready_pipe = ready_pipe
99     end
100     if set[:check_client_connection]
101       set[:listeners].each do |address|
102         if set[:listener_opts][address][:tcp_nopush] == true
103           raise ArgumentError,
104             "check_client_connection is incompatible with tcp_nopush:true"
105         end
106       end
107     end
108     set.each do |key, value|
109       value == :unset and next
110       skip.include?(key) and next
111       server.__send__("#{key}=", value)
112     end
113   end
115   def [](key) # :nodoc:
116     set[key]
117   end
119   # sets object to the +obj+ Logger-like object.  The new Logger-like
120   # object must respond to the following methods:
121   # * debug
122   # * info
123   # * warn
124   # * error
125   # * fatal
126   # The default Logger will log its output to the path specified
127   # by +stderr_path+.  If you're running Unicorn daemonized, then
128   # you must specify a path to prevent error messages from going
129   # to /dev/null.
130   def logger(obj)
131     %w(debug info warn error fatal).each do |m|
132       obj.respond_to?(m) and next
133       raise ArgumentError, "logger=#{obj} does not respond to method=#{m}"
134     end
136     set[:logger] = obj
137   end
139   # sets after_fork hook to a given block.  This block will be called by
140   # the worker after forking.  The following is an example hook which adds
141   # a per-process listener to every worker:
142   #
143   #  after_fork do |server,worker|
144   #    # per-process listener ports for debugging/admin:
145   #    addr = "127.0.0.1:#{9293 + worker.nr}"
146   #
147   #    # the negative :tries parameter indicates we will retry forever
148   #    # waiting on the existing process to exit with a 5 second :delay
149   #    # Existing options for Unicorn::Configurator#listen such as
150   #    # :backlog, :rcvbuf, :sndbuf are available here as well.
151   #    server.listen(addr, :tries => -1, :delay => 5, :backlog => 128)
152   #  end
153   def after_fork(*args, &block)
154     set_hook(:after_fork, block_given? ? block : args[0])
155   end
157   # sets before_fork got be a given Proc object.  This Proc
158   # object will be called by the master process before forking
159   # each worker.
160   def before_fork(*args, &block)
161     set_hook(:before_fork, block_given? ? block : args[0])
162   end
164   # sets the before_exec hook to a given Proc object.  This
165   # Proc object will be called by the master process right
166   # before exec()-ing the new unicorn binary.  This is useful
167   # for freeing certain OS resources that you do NOT wish to
168   # share with the reexeced child process.
169   # There is no corresponding after_exec hook (for obvious reasons).
170   def before_exec(*args, &block)
171     set_hook(:before_exec, block_given? ? block : args[0], 1)
172   end
174   # sets the timeout of worker processes to +seconds+.  Workers
175   # handling the request/app.call/response cycle taking longer than
176   # this time period will be forcibly killed (via SIGKILL).  This
177   # timeout is enforced by the master process itself and not subject
178   # to the scheduling limitations by the worker process.  Due the
179   # low-complexity, low-overhead implementation, timeouts of less
180   # than 3.0 seconds can be considered inaccurate and unsafe.
181   #
182   # For running Unicorn behind nginx, it is recommended to set
183   # "fail_timeout=0" for in your nginx configuration like this
184   # to have nginx always retry backends that may have had workers
185   # SIGKILL-ed due to timeouts.
186   #
187   #    # See http://wiki.nginx.org/NginxHttpUpstreamModule for more details
188   #    # on nginx upstream configuration:
189   #    upstream unicorn_backend {
190   #      # for UNIX domain socket setups:
191   #      server unix:/path/to/.unicorn.sock fail_timeout=0;
192   #
193   #      # for TCP setups
194   #      server 192.168.0.7:8080 fail_timeout=0;
195   #      server 192.168.0.8:8080 fail_timeout=0;
196   #      server 192.168.0.9:8080 fail_timeout=0;
197   #    }
198   def timeout(seconds)
199     set_int(:timeout, seconds, 3)
200     # POSIX says 31 days is the smallest allowed maximum timeout for select()
201     max = 30 * 60 * 60 * 24
202     set[:timeout] = seconds > max ? max : seconds
203   end
205   # sets the current number of worker_processes to +nr+.  Each worker
206   # process will serve exactly one client at a time.  You can
207   # increment or decrement this value at runtime by sending SIGTTIN
208   # or SIGTTOU respectively to the master process without reloading
209   # the rest of your Unicorn configuration.  See the SIGNALS document
210   # for more information.
211   def worker_processes(nr)
212     set_int(:worker_processes, nr, 1)
213   end
215   # sets listeners to the given +addresses+, replacing or augmenting the
216   # current set.  This is for the global listener pool shared by all
217   # worker processes.  For per-worker listeners, see the after_fork example
218   # This is for internal API use only, do not use it in your Unicorn
219   # config file.  Use listen instead.
220   def listeners(addresses) # :nodoc:
221     Array === addresses or addresses = Array(addresses)
222     addresses.map! { |addr| expand_addr(addr) }
223     set[:listeners] = addresses
224   end
226   # Adds an +address+ to the existing listener set.  May be specified more
227   # than once.  +address+ may be an Integer port number for a TCP port, an
228   # "IP_ADDRESS:PORT" for TCP listeners or a pathname for UNIX domain sockets.
229   #
230   #   listen 3000 # listen to port 3000 on all TCP interfaces
231   #   listen "127.0.0.1:3000"  # listen to port 3000 on the loopback interface
232   #   listen "/path/to/.unicorn.sock" # listen on the given Unix domain socket
233   #   listen "[::1]:3000" # listen to port 3000 on the IPv6 loopback interface
234   #
235   # When using Unix domain sockets, be sure:
236   # 1) the path matches the one used by nginx
237   # 2) uses the same filesystem namespace as the nginx process
238   # For systemd users using PrivateTmp=true (for either nginx or unicorn),
239   # this means Unix domain sockets must not be placed in /tmp
240   #
241   # The following options may be specified (but are generally not needed):
242   #
243   # [:backlog => number of clients]
244   #
245   #   This is the backlog of the listen() syscall.
246   #
247   #   Some operating systems allow negative values here to specify the
248   #   maximum allowable value.  In most cases, this number is only
249   #   recommendation and there are other OS-specific tunables and
250   #   variables that can affect this number.  See the listen(2)
251   #   syscall documentation of your OS for the exact semantics of
252   #   this.
253   #
254   #   If you are running unicorn on multiple machines, lowering this number
255   #   can help your load balancer detect when a machine is overloaded
256   #   and give requests to a different machine.
257   #
258   #   Default: 1024
259   #
260   # [:rcvbuf => bytes, :sndbuf => bytes]
261   #
262   #   Maximum receive and send buffer sizes (in bytes) of sockets.
263   #
264   #   These correspond to the SO_RCVBUF and SO_SNDBUF settings which
265   #   can be set via the setsockopt(2) syscall.  Some kernels
266   #   (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
267   #   there is no need (and it is sometimes detrimental) to specify them.
268   #
269   #   See the socket API documentation of your operating system
270   #   to determine the exact semantics of these settings and
271   #   other operating system-specific knobs where they can be
272   #   specified.
273   #
274   #   Defaults: operating system defaults
275   #
276   # [:tcp_nodelay => true or false]
277   #
278   #   Disables Nagle's algorithm on TCP sockets if +true+.
279   #
280   #   Setting this to +true+ can make streaming responses in Rails 3.1
281   #   appear more quickly at the cost of slightly higher bandwidth usage.
282   #   The effect of this option is most visible if nginx is not used,
283   #   but nginx remains highly recommended with \Unicorn.
284   #
285   #   This has no effect on UNIX sockets.
286   #
287   #   Default: +true+ (Nagle's algorithm disabled) in \Unicorn,
288   #   +true+ in Rainbows!  This defaulted to +false+ in \Unicorn
289   #   3.x
290   #
291   # [:tcp_nopush => true or false]
292   #
293   #   Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
294   #
295   #   This prevents partial TCP frames from being sent out and reduces
296   #   wakeups in nginx if it is on a different machine.  Since \Unicorn
297   #   is only designed for applications that send the response body
298   #   quickly without keepalive, sockets will always be flushed on close
299   #   to prevent delays.
300   #
301   #   This has no effect on UNIX sockets.
302   #
303   #   Default: +false+
304   #   This defaulted to +true+ in \Unicorn 3.4 - 3.7
305   #
306   # [:ipv6only => true or false]
307   #
308   #   This option makes IPv6-capable TCP listeners IPv6-only and unable
309   #   to receive IPv4 queries on dual-stack systems.  A separate IPv4-only
310   #   listener is required if this is true.
311   #
312   #   This option is only available for Ruby 1.9.2 and later.
313   #
314   #   Enabling this option for the IPv6-only listener and having a
315   #   separate IPv4 listener is recommended if you wish to support IPv6
316   #   on the same TCP port.  Otherwise, the value of \env[\"REMOTE_ADDR\"]
317   #   will appear as an ugly IPv4-mapped-IPv6 address for IPv4 clients
318   #   (e.g ":ffff:10.0.0.1" instead of just "10.0.0.1").
319   #
320   #   Default: Operating-system dependent
321   #
322   # [:reuseport => true or false]
323   #
324   #   This enables multiple, independently-started unicorn instances to
325   #   bind to the same port (as long as all the processes enable this).
326   #
327   #   This option must be used when unicorn first binds the listen socket.
328   #   It cannot be enabled when a socket is inherited via SIGUSR2
329   #   (but it will remain on if inherited), and it cannot be enabled
330   #   directly via SIGHUP.
331   #
332   #   Note: there is a chance of connections being dropped if
333   #   one of the unicorn instances is stopped while using this.
334   #
335   #   This is supported on *BSD systems and Linux 3.9 or later.
336   #
337   #   ref: https://lwn.net/Articles/542629/
338   #
339   #   Default: false (unset)
340   #
341   # [:tries => Integer]
342   #
343   #   Times to retry binding a socket if it is already in use
344   #
345   #   A negative number indicates we will retry indefinitely, this is
346   #   useful for migrations and upgrades when individual workers
347   #   are binding to different ports.
348   #
349   #   Default: 5
350   #
351   # [:delay => seconds]
352   #
353   #   Seconds to wait between successive +tries+
354   #
355   #   Default: 0.5 seconds
356   #
357   # [:umask => mode]
358   #
359   #   Sets the file mode creation mask for UNIX sockets.  If specified,
360   #   this is usually in octal notation.
361   #
362   #   Typically UNIX domain sockets are created with more liberal
363   #   file permissions than the rest of the application.  By default,
364   #   we create UNIX domain sockets to be readable and writable by
365   #   all local users to give them the same accessibility as
366   #   locally-bound TCP listeners.
367   #
368   #   This has no effect on TCP listeners.
369   #
370   #   Default: 0000 (world-read/writable)
371   #
372   # [:tcp_defer_accept => Integer]
373   #
374   #   Defer accept() until data is ready (Linux-only)
375   #
376   #   For Linux 2.6.32 and later, this is the number of retransmits to
377   #   defer an accept() for if no data arrives, but the client will
378   #   eventually be accepted after the specified number of retransmits
379   #   regardless of whether data is ready.
380   #
381   #   For Linux before 2.6.32, this is a boolean option, and
382   #   accepts are _always_ deferred indefinitely if no data arrives.
383   #   This is similar to <code>:accept_filter => "dataready"</code>
384   #   under FreeBSD.
385   #
386   #   Specifying +true+ is synonymous for the default value(s) below,
387   #   and +false+ or +nil+ is synonymous for a value of zero.
388   #
389   #   A value of +1+ is a good optimization for local networks
390   #   and trusted clients.  For Rainbows! and Zbatery users, a higher
391   #   value (e.g. +60+) provides more protection against some
392   #   denial-of-service attacks.  There is no good reason to ever
393   #   disable this with a +zero+ value when serving HTTP.
394   #
395   #   Default: 1 retransmit for \Unicorn, 60 for Rainbows! 0.95.0\+
396   #
397   # [:accept_filter => String]
398   #
399   #   defer accept() until data is ready (FreeBSD-only)
400   #
401   #   This enables either the "dataready" or (default) "httpready"
402   #   accept() filter under FreeBSD.  This is intended as an
403   #   optimization to reduce context switches with common GET/HEAD
404   #   requests.  For Rainbows! and Zbatery users, this provides
405   #   some protection against certain denial-of-service attacks, too.
406   #
407   #   There is no good reason to change from the default.
408   #
409   #   Default: "httpready"
410   def listen(address, options = {})
411     address = expand_addr(address)
412     if String === address
413       [ :umask, :backlog, :sndbuf, :rcvbuf, :tries ].each do |key|
414         value = options[key] or next
415         Integer === value or
416           raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
417       end
418       [ :tcp_nodelay, :tcp_nopush, :ipv6only, :reuseport ].each do |key|
419         (value = options[key]).nil? and next
420         TrueClass === value || FalseClass === value or
421           raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
422       end
423       unless (value = options[:delay]).nil?
424         Numeric === value or
425           raise ArgumentError, "not numeric: delay=#{value.inspect}"
426       end
427       set[:listener_opts][address].merge!(options)
428     end
430     set[:listeners] << address
431   end
433   # sets the +path+ for the PID file of the unicorn master process
434   def pid(path); set_path(:pid, path); end
436   # Enabling this preloads an application before forking worker
437   # processes.  This allows memory savings when using a
438   # copy-on-write-friendly GC but can cause bad things to happen when
439   # resources like sockets are opened at load time by the master
440   # process and shared by multiple children.  People enabling this are
441   # highly encouraged to look at the before_fork/after_fork hooks to
442   # properly close/reopen sockets.  Files opened for logging do not
443   # have to be reopened as (unbuffered-in-userspace) files opened with
444   # the File::APPEND flag are written to atomically on UNIX.
445   #
446   # In addition to reloading the unicorn-specific config settings,
447   # SIGHUP will reload application code in the working
448   # directory/symlink when workers are gracefully restarted when
449   # preload_app=false (the default).  As reloading the application
450   # sometimes requires RubyGems updates, +Gem.refresh+ is always
451   # called before the application is loaded (for RubyGems users).
452   #
453   # During deployments, care should _always_ be taken to ensure your
454   # applications are properly deployed and running.  Using
455   # preload_app=false (the default) means you _must_ check if
456   # your application is responding properly after a deployment.
457   # Improperly deployed applications can go into a spawn loop
458   # if the application fails to load.  While your children are
459   # in a spawn loop, it is is possible to fix an application
460   # by properly deploying all required code and dependencies.
461   # Using preload_app=true means any application load error will
462   # cause the master process to exit with an error.
464   def preload_app(bool)
465     set_bool(:preload_app, bool)
466   end
468   # Toggles making \env[\"rack.input\"] rewindable.
469   # Disabling rewindability can improve performance by lowering
470   # I/O and memory usage for applications that accept uploads.
471   # Keep in mind that the Rack 1.x spec requires
472   # \env[\"rack.input\"] to be rewindable, so this allows
473   # intentionally violating the current Rack 1.x spec.
474   #
475   # +rewindable_input+ defaults to +true+ when used with Rack 1.x for
476   # Rack conformance.  When Rack 2.x is finalized, this will most
477   # likely default to +false+ while still conforming to the newer
478   # (less demanding) spec.
479   def rewindable_input(bool)
480     set_bool(:rewindable_input, bool)
481   end
483   # The maximum size (in +bytes+) to buffer in memory before
484   # resorting to a temporary file.  Default is 112 kilobytes.
485   # This option has no effect if "rewindable_input" is set to
486   # +false+.
487   def client_body_buffer_size(bytes)
488     set_int(:client_body_buffer_size, bytes, 0)
489   end
491   # When enabled, unicorn will check the client connection by writing
492   # the beginning of the HTTP headers before calling the application.
493   #
494   # This will prevent calling the application for clients who have
495   # disconnected while their connection was queued.
496   #
497   # This only affects clients connecting over Unix domain sockets
498   # and TCP via loopback (127.*.*.*).  It is unlikely to detect
499   # disconnects if the client is on a remote host (even on a fast LAN).
500   #
501   # This option cannot be used in conjunction with :tcp_nopush.
502   def check_client_connection(bool)
503     set_bool(:check_client_connection, bool)
504   end
506   # Allow redirecting $stderr to a given path.  Unlike doing this from
507   # the shell, this allows the unicorn process to know the path its
508   # writing to and rotate the file if it is used for logging.  The
509   # file will be opened with the File::APPEND flag and writes
510   # synchronized to the kernel (but not necessarily to _disk_) so
511   # multiple processes can safely append to it.
512   #
513   # If you are daemonizing and using the default +logger+, it is important
514   # to specify this as errors will otherwise be lost to /dev/null.
515   # Some applications/libraries may also triggering warnings that go to
516   # stderr, and they will end up here.
517   def stderr_path(path)
518     set_path(:stderr_path, path)
519   end
521   # Same as stderr_path, except for $stdout.  Not many Rack applications
522   # write to $stdout, but any that do will have their output written here.
523   # It is safe to point this to the same location a stderr_path.
524   # Like stderr_path, this defaults to /dev/null when daemonized.
525   def stdout_path(path)
526     set_path(:stdout_path, path)
527   end
529   # sets the working directory for Unicorn.  This ensures SIGUSR2 will
530   # start a new instance of Unicorn in this directory.  This may be
531   # a symlink, a common scenario for Capistrano users.  Unlike
532   # all other Unicorn configuration directives, this binds immediately
533   # for error checking and cannot be undone by unsetting it in the
534   # configuration file and reloading.
535   def working_directory(path)
536     # just let chdir raise errors
537     path = File.expand_path(path)
538     if config_file &&
539        config_file[0] != ?/ &&
540        ! File.readable?("#{path}/#{config_file}")
541       raise ArgumentError,
542             "config_file=#{config_file} would not be accessible in" \
543             " working_directory=#{path}"
544     end
545     Dir.chdir(path)
546     Unicorn::HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
547   end
549   # Runs worker processes as the specified +user+ and +group+.
550   # The master process always stays running as the user who started it.
551   # This switch will occur after calling the after_fork hook, and only
552   # if the Worker#user method is not called in the after_fork hook
553   # +group+ is optional and will not change if unspecified.
554   def user(user, group = nil)
555     # raises ArgumentError on invalid user/group
556     Etc.getpwnam(user)
557     Etc.getgrnam(group) if group
558     set[:user] = [ user, group ]
559   end
561   # Sets whether or not the parser will trust X-Forwarded-Proto and
562   # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
563   # Rainbows!/Zbatery installations facing untrusted clients directly
564   # should set this to +false+.  This is +true+ by default as Unicorn
565   # is designed to only sit behind trusted nginx proxies.
566   #
567   # This has never been publically documented and is subject to removal
568   # in future releases.
569   def trust_x_forwarded(bool) # :nodoc:
570     set_bool(:trust_x_forwarded, bool)
571   end
573   # expands "unix:path/to/foo" to a socket relative to the current path
574   # expands pathnames of sockets if relative to "~" or "~username"
575   # expands "*:port and ":port" to "0.0.0.0:port"
576   def expand_addr(address) #:nodoc:
577     return "0.0.0.0:#{address}" if Integer === address
578     return address unless String === address
580     case address
581     when %r{\Aunix:(.*)\z}
582       File.expand_path($1)
583     when %r{\A~}
584       File.expand_path(address)
585     when %r{\A(?:\*:)?(\d+)\z}
586       "0.0.0.0:#$1"
587     when %r{\A\[([a-fA-F0-9:]+)\]\z}, %r/\A((?:\d+\.){3}\d+)\z/
588       canonicalize_tcp($1, 80)
589     when %r{\A\[([a-fA-F0-9:]+)\]:(\d+)\z}, %r{\A(.*):(\d+)\z}
590       canonicalize_tcp($1, $2.to_i)
591     else
592       address
593     end
594   end
596 private
597   def set_int(var, n, min) #:nodoc:
598     Integer === n or raise ArgumentError, "not an integer: #{var}=#{n.inspect}"
599     n >= min or raise ArgumentError, "too low (< #{min}): #{var}=#{n.inspect}"
600     set[var] = n
601   end
603   def canonicalize_tcp(addr, port)
604     packed = Socket.pack_sockaddr_in(port, addr)
605     port, addr = Socket.unpack_sockaddr_in(packed)
606     /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
607   end
609   def set_path(var, path) #:nodoc:
610     case path
611     when NilClass, String
612       set[var] = path
613     else
614       raise ArgumentError
615     end
616   end
618   def check_bool(var, bool) # :nodoc:
619     case bool
620     when true, false
621       return bool
622     end
623     raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
624   end
626   def set_bool(var, bool) #:nodoc:
627     set[var] = check_bool(var, bool)
628   end
630   def set_hook(var, my_proc, req_arity = 2) #:nodoc:
631     case my_proc
632     when Proc
633       arity = my_proc.arity
634       (arity == req_arity) or \
635         raise ArgumentError,
636               "#{var}=#{my_proc.inspect} has invalid arity: " \
637               "#{arity} (need #{req_arity})"
638     when NilClass
639       my_proc = DEFAULTS[var]
640     else
641       raise ArgumentError, "invalid type: #{var}=#{my_proc.inspect}"
642     end
643     set[var] = my_proc
644   end
646   # this is called _after_ working_directory is bound.  This only
647   # parses the embedded switches in .ru files
648   # (for "rackup" compatibility)
649   def parse_rackup_file # :nodoc:
650     ru = RACKUP[:file] or return # we only return here in unit tests
652     # :rails means use (old) Rails autodetect
653     if ru == :rails
654       File.readable?('config.ru') or return
655       ru = 'config.ru'
656     end
658     File.readable?(ru) or
659       raise ArgumentError, "rackup file (#{ru}) not readable"
661     # it could be a .rb file, too, we don't parse those manually
662     ru =~ /\.ru\z/ or return
664     /^#\\(.*)/ =~ File.read(ru) or return
665     RACKUP[:optparse].parse!($1.split(/\s+/))
667     if RACKUP[:daemonize]
668       # unicorn_rails wants a default pid path, (not plain 'unicorn')
669       if after_reload
670         spid = set[:pid]
671         pid('tmp/pids/unicorn.pid') if spid.nil? || spid == :unset
672       end
673       unless RACKUP[:daemonized]
674         Unicorn::Launcher.daemonize!(RACKUP[:options])
675         RACKUP[:ready_pipe] = RACKUP[:options].delete(:ready_pipe)
676       end
677     end
678   end