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