configurator: documentation for new accept options
[unicorn.git] / lib / unicorn / configurator.rb
blob3cf0d728bb88824c5c9824239018e71b0bfcc615
1 # -*- encoding: binary -*-
3 require 'socket'
4 require 'logger'
6 module Unicorn
8   # Implements a simple DSL for configuring a Unicorn server.
9   #
10   # See http://unicorn.bogomips.org/examples/unicorn.conf.rb and
11   # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
12   # example configuration files.  An example config file for use with
13   # nginx is also available at
14   # http://unicorn.bogomips.org/examples/nginx.conf
15   class Configurator < Struct.new(:set, :config_file, :after_reload)
16     # :stopdoc:
17     # used to stash stuff for deferred processing of cli options in
18     # config.ru after "working_directory" is bound.  Do not rely on
19     # this being around later on...
20     RACKUP = {}
21     # :startdoc:
23     # Default settings for Unicorn
24     DEFAULTS = {
25       :timeout => 60,
26       :logger => Logger.new($stderr),
27       :worker_processes => 1,
28       :after_fork => lambda { |server, worker|
29           server.logger.info("worker=#{worker.nr} spawned pid=#{$$}")
30         },
31       :before_fork => lambda { |server, worker|
32           server.logger.info("worker=#{worker.nr} spawning...")
33         },
34       :before_exec => lambda { |server|
35           server.logger.info("forked child re-executing...")
36         },
37       :pid => nil,
38       :preload_app => false,
39     }
41     def initialize(defaults = {}) #:nodoc:
42       self.set = Hash.new(:unset)
43       use_defaults = defaults.delete(:use_defaults)
44       self.config_file = defaults.delete(:config_file)
46       # after_reload is only used by unicorn_rails, unsupported otherwise
47       self.after_reload = defaults.delete(:after_reload)
49       set.merge!(DEFAULTS) if use_defaults
50       defaults.each { |key, value| self.send(key, value) }
51       Hash === set[:listener_opts] or
52           set[:listener_opts] = Hash.new { |hash,key| hash[key] = {} }
53       Array === set[:listeners] or set[:listeners] = []
54       reload
55     end
57     def reload #:nodoc:
58       instance_eval(File.read(config_file), config_file) if config_file
60       parse_rackup_file
62       # unicorn_rails creates dirs here after working_directory is bound
63       after_reload.call if after_reload
65       # working_directory binds immediately (easier error checking that way),
66       # now ensure any paths we changed are correctly set.
67       [ :pid, :stderr_path, :stdout_path ].each do |var|
68         String === (path = set[var]) or next
69         path = File.expand_path(path)
70         File.writable?(path) || File.writable?(File.dirname(path)) or \
71               raise ArgumentError, "directory for #{var}=#{path} not writable"
72       end
73     end
75     def commit!(server, options = {}) #:nodoc:
76       skip = options[:skip] || []
77       if ready_pipe = RACKUP.delete(:ready_pipe)
78         server.ready_pipe = ready_pipe
79       end
80       set.each do |key, value|
81         value == :unset and next
82         skip.include?(key) and next
83         server.__send__("#{key}=", value)
84       end
85     end
87     def [](key) # :nodoc:
88       set[key]
89     end
91     # sets object to the +new+ Logger-like object.  The new logger-like
92     # object must respond to the following methods:
93     #  +debug+, +info+, +warn+, +error+, +fatal+
94     # The default Logger will log its output to the path specified
95     # by +stderr_path+.  If you're running Unicorn daemonized, then
96     # you must specify a path to prevent error messages from going
97     # to /dev/null.
98     def logger(new)
99       %w(debug info warn error fatal).each do |m|
100         new.respond_to?(m) and next
101         raise ArgumentError, "logger=#{new} does not respond to method=#{m}"
102       end
104       set[:logger] = new
105     end
107     # sets after_fork hook to a given block.  This block will be called by
108     # the worker after forking.  The following is an example hook which adds
109     # a per-process listener to every worker:
110     #
111     #  after_fork do |server,worker|
112     #    # per-process listener ports for debugging/admin:
113     #    addr = "127.0.0.1:#{9293 + worker.nr}"
114     #
115     #    # the negative :tries parameter indicates we will retry forever
116     #    # waiting on the existing process to exit with a 5 second :delay
117     #    # Existing options for Unicorn::Configurator#listen such as
118     #    # :backlog, :rcvbuf, :sndbuf are available here as well.
119     #    server.listen(addr, :tries => -1, :delay => 5, :backlog => 128)
120     #
121     #    # drop permissions to "www-data" in the worker
122     #    # generally there's no reason to start Unicorn as a priviledged user
123     #    # as it is not recommended to expose Unicorn to public clients.
124     #    worker.user('www-data', 'www-data') if Process.euid == 0
125     #  end
126     def after_fork(*args, &block)
127       set_hook(:after_fork, block_given? ? block : args[0])
128     end
130     # sets before_fork got be a given Proc object.  This Proc
131     # object will be called by the master process before forking
132     # each worker.
133     def before_fork(*args, &block)
134       set_hook(:before_fork, block_given? ? block : args[0])
135     end
137     # sets the before_exec hook to a given Proc object.  This
138     # Proc object will be called by the master process right
139     # before exec()-ing the new unicorn binary.  This is useful
140     # for freeing certain OS resources that you do NOT wish to
141     # share with the reexeced child process.
142     # There is no corresponding after_exec hook (for obvious reasons).
143     def before_exec(*args, &block)
144       set_hook(:before_exec, block_given? ? block : args[0], 1)
145     end
147     # sets the timeout of worker processes to +seconds+.  Workers
148     # handling the request/app.call/response cycle taking longer than
149     # this time period will be forcibly killed (via SIGKILL).  This
150     # timeout is enforced by the master process itself and not subject
151     # to the scheduling limitations by the worker process.  Due the
152     # low-complexity, low-overhead implementation, timeouts of less
153     # than 3.0 seconds can be considered inaccurate and unsafe.
154     #
155     # For running Unicorn behind nginx, it is recommended to set
156     # "fail_timeout=0" for in your nginx configuration like this
157     # to have nginx always retry backends that may have had workers
158     # SIGKILL-ed due to timeouts.
159     #
160     #    # See http://wiki.nginx.org/NginxHttpUpstreamModule for more details
161     #    # on nginx upstream configuration:
162     #    upstream unicorn_backend {
163     #      # for UNIX domain socket setups:
164     #      server unix:/path/to/unicorn.sock fail_timeout=0;
165     #
166     #      # for TCP setups
167     #      server 192.168.0.7:8080 fail_timeout=0;
168     #      server 192.168.0.8:8080 fail_timeout=0;
169     #      server 192.168.0.9:8080 fail_timeout=0;
170     #    }
171     def timeout(seconds)
172       Numeric === seconds or raise ArgumentError,
173                                   "not numeric: timeout=#{seconds.inspect}"
174       seconds >= 3 or raise ArgumentError,
175                                   "too low: timeout=#{seconds.inspect}"
176       set[:timeout] = seconds
177     end
179     # sets the current number of worker_processes to +nr+.  Each worker
180     # process will serve exactly one client at a time.  You can
181     # increment or decrement this value at runtime by sending SIGTTIN
182     # or SIGTTOU respectively to the master process without reloading
183     # the rest of your Unicorn configuration.  See the SIGNALS document
184     # for more information.
185     def worker_processes(nr)
186       Integer === nr or raise ArgumentError,
187                              "not an integer: worker_processes=#{nr.inspect}"
188       nr >= 0 or raise ArgumentError,
189                              "not non-negative: worker_processes=#{nr.inspect}"
190       set[:worker_processes] = nr
191     end
193     # sets listeners to the given +addresses+, replacing or augmenting the
194     # current set.  This is for the global listener pool shared by all
195     # worker processes.  For per-worker listeners, see the after_fork example
196     # This is for internal API use only, do not use it in your Unicorn
197     # config file.  Use listen instead.
198     def listeners(addresses) # :nodoc:
199       Array === addresses or addresses = Array(addresses)
200       addresses.map! { |addr| expand_addr(addr) }
201       set[:listeners] = addresses
202     end
204     # adds an +address+ to the existing listener set.
205     #
206     # The following options may be specified (but are generally not needed):
207     #
208     # +:backlog+: this is the backlog of the listen() syscall.
209     #
210     # Some operating systems allow negative values here to specify the
211     # maximum allowable value.  In most cases, this number is only
212     # recommendation and there are other OS-specific tunables and
213     # variables that can affect this number.  See the listen(2)
214     # syscall documentation of your OS for the exact semantics of
215     # this.
216     #
217     # If you are running unicorn on multiple machines, lowering this number
218     # can help your load balancer detect when a machine is overloaded
219     # and give requests to a different machine.
220     #
221     # Default: 1024
222     #
223     # +:rcvbuf+, +:sndbuf+: maximum receive and send buffer sizes of sockets
224     #
225     # These correspond to the SO_RCVBUF and SO_SNDBUF settings which
226     # can be set via the setsockopt(2) syscall.  Some kernels
227     # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
228     # there is no need (and it is sometimes detrimental) to specify them.
229     #
230     # See the socket API documentation of your operating system
231     # to determine the exact semantics of these settings and
232     # other operating system-specific knobs where they can be
233     # specified.
234     #
235     # Defaults: operating system defaults
236     #
237     # +:tcp_nodelay+: disables Nagle's algorithm on TCP sockets
238     #
239     # This has no effect on UNIX sockets.
240     #
241     # Default: operating system defaults (usually Nagle's algorithm enabled)
242     #
243     # +:tcp_nopush+: enables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
244     #
245     # This will prevent partial TCP frames from being sent out.
246     # Enabling +tcp_nopush+ is generally not needed or recommended as
247     # controlling +tcp_nodelay+ already provides sufficient latency
248     # reduction whereas Unicorn does not know when the best times are
249     # for flushing corked sockets.
250     #
251     # This has no effect on UNIX sockets.
252     #
253     # +:tries+: times to retry binding a socket if it is already in use
254     #
255     # A negative number indicates we will retry indefinitely, this is
256     # useful for migrations and upgrades when individual workers
257     # are binding to different ports.
258     #
259     # Default: 5
260     #
261     # +:delay+: seconds to wait between successive +tries+
262     #
263     # Default: 0.5 seconds
264     #
265     # +:umask+: sets the file mode creation mask for UNIX sockets
266     #
267     # Typically UNIX domain sockets are created with more liberal
268     # file permissions than the rest of the application.  By default,
269     # we create UNIX domain sockets to be readable and writable by
270     # all local users to give them the same accessibility as
271     # locally-bound TCP listeners.
272     #
273     # This has no effect on TCP listeners.
274     #
275     # Default: 0 (world read/writable)
276     #
277     # +:tcp_defer_accept:+ defer accept() until data is ready (Linux-only)
278     #
279     # For Linux 2.6.32 and later, this is the number of retransmits to
280     # defer an accept() for if no data arrives, but the client will
281     # eventually be accepted after the specified number of retransmits
282     # regardless of whether data is ready.
283     #
284     # For Linux before 2.6.32, this is a boolean option, and
285     # accepts are _always_ deferred indefinitely if no data arrives.
286     # This is similar to <code>:accept_filter => "dataready"</code>
287     # under FreeBSD.
288     #
289     # Specifying +true+ is synonymous for the default value(s) below,
290     # and +false+ or +nil+ is synonymous for a value of zero.
291     #
292     # A value of +1+ is a good optimization for local networks
293     # and trusted clients.  For Rainbows! and Zbatery users, a higher
294     # value (e.g. +60+) provides more protection against some
295     # denial-of-service attacks.  There is no good reason to ever
296     # disable this with a +zero+ value when serving HTTP.
297     #
298     # Default: 1 retransmit for \Unicorn, 60 for Rainbows! 0.95.0\+
299     #
300     # +:accept_filter: defer accept() until data is ready (FreeBSD-only)
301     #
302     # This enables either the "dataready" or (default) "httpready"
303     # accept() filter under FreeBSD.  This is intended as an
304     # optimization to reduce context switches with common GET/HEAD
305     # requests.  For Rainbows! and Zbatery users, this provides
306     # some protection against certain denial-of-service attacks, too.
307     #
308     # There is no good reason to change from the default.
309     #
310     # Default: "httpready"
311     def listen(address, opt = {})
312       address = expand_addr(address)
313       if String === address
314         [ :umask, :backlog, :sndbuf, :rcvbuf, :tries ].each do |key|
315           value = opt[key] or next
316           Integer === value or
317             raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
318         end
319         [ :tcp_nodelay, :tcp_nopush ].each do |key|
320           (value = opt[key]).nil? and next
321           TrueClass === value || FalseClass === value or
322             raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
323         end
324         unless (value = opt[:delay]).nil?
325           Numeric === value or
326             raise ArgumentError, "not numeric: delay=#{value.inspect}"
327         end
328         set[:listener_opts][address].merge!(opt)
329       end
331       set[:listeners] << address
332     end
334     # sets the +path+ for the PID file of the unicorn master process
335     def pid(path); set_path(:pid, path); end
337     # Enabling this preloads an application before forking worker
338     # processes.  This allows memory savings when using a
339     # copy-on-write-friendly GC but can cause bad things to happen when
340     # resources like sockets are opened at load time by the master
341     # process and shared by multiple children.  People enabling this are
342     # highly encouraged to look at the before_fork/after_fork hooks to
343     # properly close/reopen sockets.  Files opened for logging do not
344     # have to be reopened as (unbuffered-in-userspace) files opened with
345     # the File::APPEND flag are written to atomically on UNIX.
346     #
347     # In addition to reloading the unicorn-specific config settings,
348     # SIGHUP will reload application code in the working
349     # directory/symlink when workers are gracefully restarted when
350     # preload_app=false (the default).  As reloading the application
351     # sometimes requires RubyGems updates, +Gem.refresh+ is always
352     # called before the application is loaded (for RubyGems users).
353     #
354     # During deployments, care should _always_ be taken to ensure your
355     # applications are properly deployed and running.  Using
356     # preload_app=false (the default) means you _must_ check if
357     # your application is responding properly after a deployment.
358     # Improperly deployed applications can go into a spawn loop
359     # if the application fails to load.  While your children are
360     # in a spawn loop, it is is possible to fix an application
361     # by properly deploying all required code and dependencies.
362     # Using preload_app=true means any application load error will
363     # cause the master process to exit with an error.
365     def preload_app(bool)
366       case bool
367       when TrueClass, FalseClass
368         set[:preload_app] = bool
369       else
370         raise ArgumentError, "preload_app=#{bool.inspect} not a boolean"
371       end
372     end
374     # Allow redirecting $stderr to a given path.  Unlike doing this from
375     # the shell, this allows the unicorn process to know the path its
376     # writing to and rotate the file if it is used for logging.  The
377     # file will be opened with the File::APPEND flag and writes
378     # synchronized to the kernel (but not necessarily to _disk_) so
379     # multiple processes can safely append to it.
380     #
381     # If you are daemonizing and using the default +logger+, it is important
382     # to specify this as errors will otherwise be lost to /dev/null.
383     # Some applications/libraries may also triggering warnings that go to
384     # stderr, and they will end up here.
385     def stderr_path(path)
386       set_path(:stderr_path, path)
387     end
389     # Same as stderr_path, except for $stdout.  Not many Rack applications
390     # write to $stdout, but any that do will have their output written here.
391     # It is safe to point this to the same location a stderr_path.
392     # Like stderr_path, this defaults to /dev/null when daemonized.
393     def stdout_path(path)
394       set_path(:stdout_path, path)
395     end
397     # sets the working directory for Unicorn.  This ensures SIGUSR2 will
398     # start a new instance of Unicorn in this directory.  This may be
399     # a symlink, a common scenario for Capistrano users.
400     def working_directory(path)
401       # just let chdir raise errors
402       path = File.expand_path(path)
403       if config_file &&
404          config_file[0] != ?/ &&
405          ! File.readable?("#{path}/#{config_file}")
406         raise ArgumentError,
407               "config_file=#{config_file} would not be accessible in" \
408               " working_directory=#{path}"
409       end
410       Dir.chdir(path)
411       HttpServer::START_CTX[:cwd] = ENV["PWD"] = path
412     end
414     # Runs worker processes as the specified +user+ and +group+.
415     # The master process always stays running as the user who started it.
416     # This switch will occur after calling the after_fork hook, and only
417     # if the Worker#user method is not called in the after_fork hook
418     def user(user, group = nil)
419       # raises ArgumentError on invalid user/group
420       Etc.getpwnam(user)
421       Etc.getgrnam(group) if group
422       set[:user] = [ user, group ]
423     end
425     # expands "unix:path/to/foo" to a socket relative to the current path
426     # expands pathnames of sockets if relative to "~" or "~username"
427     # expands "*:port and ":port" to "0.0.0.0:port"
428     def expand_addr(address) #:nodoc
429       return "0.0.0.0:#{address}" if Integer === address
430       return address unless String === address
432       case address
433       when %r{\Aunix:(.*)\z}
434         File.expand_path($1)
435       when %r{\A~}
436         File.expand_path(address)
437       when %r{\A(?:\*:)?(\d+)\z}
438         "0.0.0.0:#$1"
439       when %r{\A(.*):(\d+)\z}
440         # canonicalize the name
441         packed = Socket.pack_sockaddr_in($2.to_i, $1)
442         Socket.unpack_sockaddr_in(packed).reverse!.join(':')
443       else
444         address
445       end
446     end
448   private
450     def set_path(var, path) #:nodoc:
451       case path
452       when NilClass, String
453         set[var] = path
454       else
455         raise ArgumentError
456       end
457     end
459     def set_hook(var, my_proc, req_arity = 2) #:nodoc:
460       case my_proc
461       when Proc
462         arity = my_proc.arity
463         (arity == req_arity) or \
464           raise ArgumentError,
465                 "#{var}=#{my_proc.inspect} has invalid arity: " \
466                 "#{arity} (need #{req_arity})"
467       when NilClass
468         my_proc = DEFAULTS[var]
469       else
470         raise ArgumentError, "invalid type: #{var}=#{my_proc.inspect}"
471       end
472       set[var] = my_proc
473     end
475     # this is called _after_ working_directory is bound.  This only
476     # parses the embedded switches in .ru files
477     # (for "rackup" compatibility)
478     def parse_rackup_file # :nodoc:
479       ru = RACKUP[:file] or return # we only return here in unit tests
481       # :rails means use (old) Rails autodetect
482       if ru == :rails
483         File.readable?('config.ru') or return
484         ru = 'config.ru'
485       end
487       File.readable?(ru) or
488         raise ArgumentError, "rackup file (#{ru}) not readable"
490       # it could be a .rb file, too, we don't parse those manually
491       ru =~ /\.ru\z/ or return
493       /^#\\(.*)/ =~ File.read(ru) or return
494       RACKUP[:optparse].parse!($1.split(/\s+/))
496       # XXX ugly as hell, WILL FIX in 2.x (along with Rainbows!/Zbatery)
497       host, port, set_listener, options, daemonize =
498                       eval("[ host, port, set_listener, options, daemonize ]",
499                            TOPLEVEL_BINDING)
501       # XXX duplicate code from bin/unicorn{,_rails}
502       set[:listeners] << "#{host}:#{port}" if set_listener
504       if daemonize
505         # unicorn_rails wants a default pid path, (not plain 'unicorn')
506         if after_reload
507           spid = set[:pid]
508           pid('tmp/pids/unicorn.pid') if spid.nil? || spid == :unset
509         end
510         unless RACKUP[:daemonized]
511           Unicorn::Launcher.daemonize!(options)
512           RACKUP[:ready_pipe] = options.delete(:ready_pipe)
513         end
514       end
515     end
517   end