lib/rainbows/configurator.rb in rainbows-3.2.0 vs lib/rainbows/configurator.rb in rainbows-3.3.0

- old
+ new

@@ -1,51 +1,205 @@ # -*- encoding: binary -*- # This module adds \Rainbows! to the # {Unicorn::Configurator}[http://unicorn.bogomips.org/Unicorn/Configurator.html] +# \Rainbows!-specific configuration options must be inside a the Rainbows! +# block, otherwise Unicorn::Configurator directives may be used anwwhere +# in the file. +# +# Rainbows! do +# use :ThreadSpawn # concurrency model to use +# worker_connections 400 +# keepalive_timeout 0 # zero disables keepalives entirely +# client_max_body_size 5*1024*1024 # 5 megabytes +# keepalive_requests 666 # default:100 +# client_header_buffer_size 2 * 1024 # 2 kilobytes +# end +# +# # the rest of the Unicorn configuration... +# worker_processes 8 +# stderr_path "/path/to/error.log" +# stdout_path "/path/to/output.log" module Rainbows::Configurator + Unicorn::Configurator::DEFAULTS.merge!({ + :use => Rainbows::Base, + :worker_connections => 50, + :keepalive_timeout => 5, + :keepalive_requests => 100, + :client_max_body_size => 1024 * 1024, + :client_header_buffer_size => 1024, + :copy_stream => IO.respond_to?(:copy_stream) ? IO : false, + }) - # configures \Rainbows! with a given concurrency model to +use+ and - # a +worker_connections+ upper-bound. This method may be called - # inside a Unicorn/\Rainbows! configuration file: + # Configures \Rainbows! with a given concurrency model to +use+ and + # a +worker_connections+ upper-bound. This method should be called + # inside a Unicorn/\Rainbows! configuration file. # + # All other methods in Rainbows::Configurator must be called + # inside this block. + def Rainbows!(&block) + block_given? or raise ArgumentError, "Rainbows! requires a block" + @block = true + instance_eval(&block) + ensure + @block = false + end + + def check! # :nodoc: + @block or abort "must be inside a Rainbows! block" + end + + # This limits the number of connected clients per-process. The total + # number of clients on a server is +worker_processes+ * +worker_connections+. + # + # This option has no effect with the Base concurrency model, which is + # limited to +1+. + # + # Default: 50 + def worker_connections(clients) + check! + set_int(:worker_connections, clients, 1) + end + + # Select a concurrency model for use with \Rainbows!. You must select + # this with a Symbol (prefixed with ":"). Thus if you wish to select + # the Rainbows::ThreadSpawn concurrency model, you would use: + # # Rainbows! do - # use :ThreadSpawn # concurrency model to use - # worker_connections 400 - # keepalive_timeout 0 # zero disables keepalives entirely - # client_max_body_size 5*1024*1024 # 5 megabytes - # keepalive_requests 666 # default:100 + # use :ThreadSpawn # end # - # # the rest of the Unicorn configuration - # worker_processes 8 + # See the {Summary}[link:Summary.html] document for a summary of + # supported concurrency models. +options+ may be specified for some + # concurrency models, but the majority do not support them. # - # See the documentation for the respective Revactor, ThreadSpawn, - # and ThreadPool classes for descriptions and recommendations for - # each of them. The total number of clients we're able to serve is - # +worker_processes+ * +worker_connections+, so in the above example - # we can serve 8 * 400 = 3200 clients concurrently. + # Default: :Base (no concurrency) + def use(model, *options) + check! + mod = begin + Rainbows.const_get(model) + rescue NameError => e + warn "error loading #{model.inspect}: #{e}" + e.backtrace.each { |l| warn l } + abort "concurrency model #{model.inspect} not supported" + end + Module === mod or abort "concurrency model #{model.inspect} not supported" + options.each do |opt| + case opt + when Hash + Rainbows::O.merge!(opt) + when Symbol + Rainbows::O[opt] = true + else + abort "cannot handle option: #{opt.inspect} in #{options.inspect}" + end + end + mod.setup if mod.respond_to?(:setup) + set[:use] = mod + end + + # Sets the value (in seconds) the server will wait for a client in + # between requests. The default value should be enough under most + # conditions for browsers to render the page and start retrieving + # extra elements. # - # The default is +keepalive_timeout+ is 5 seconds, which should be - # enough under most conditions for browsers to render the page and - # start retrieving extra elements for. Increasing this beyond 5 - # seconds is not recommended. Zero disables keepalive entirely - # (but pipelining fully-formed requests is still works). + # Setting this value to +0+ disables keepalive entirely # - # The default +client_max_body_size+ is 1 megabyte (1024 * 1024 bytes), - # setting this to +nil+ will disable body size checks and allow any - # size to be specified. + # Default: 5 seconds + def keepalive_timeout(seconds) + check! + set_int(:keepalive_timeout, seconds, 0) + end + + # This limits the number of requests which can be made over a keep-alive + # connection. This is used to prevent single client from monopolizing + # the server and to improve fairness when load-balancing across multiple + # machines by forcing a client to reconnect. This may be helpful + # in mitigating some denial-of-service attacks. # - # The default +keepalive_requests+ is 100, meaning a client may - # complete 100 keepalive requests after the initial request before - # \Rainbows! forces a disconnect. Lowering this can improve - # load-balancing characteristics as it forces HTTP/1.1 clients to - # reconnect after the specified number of requests, hopefully to a - # less busy host or worker process. This may also be used to mitigate - # denial-of-service attacks that use HTTP pipelining. - def Rainbows!(&block) - block_given? or raise ArgumentError, "Rainbows! requires a block" - Rainbows::HttpServer.setup(block) + # Default: 100 requests + def keepalive_requests(count) + check! + case count + when nil, Integer + set[:keepalive_requests] = count + else + abort "not an integer or nil: keepalive_requests=#{count.inspect}" + end + end + + # Limits the maximum size of a request body for all requests. + # Setting this to +nil+ disables the maximum size check. + # + # Default: 1 megabyte (1048576 bytes) + # + # If you want endpoint-specific upload limits and use a + # "rack.input"-streaming concurrency model, see the Rainbows::MaxBody + def client_max_body_size(bytes) + check! + err = "client_max_body_size must be nil or a non-negative Integer" + case bytes + when nil + when Integer + bytes >= 0 or abort err + else + abort err + end + set[:client_max_body_size] = bytes + end + + # This governs the amount of memory allocated for an individual read(2) or + # recv(2) system call when reading headers. Applications that make minimal + # use of cookies should not increase this from the default. + # + # Rails applications using session cookies may want to increase this to + # 2048 bytes or more depending on expected request sizes. + # + # Increasing this will increase overall memory usage to your application, + # as you will need at least this amount of memory for every connected client. + # + # Default: 1024 bytes + def client_header_buffer_size(bytes) + check! + set_int(:client_header_buffer_size, bytes, 1) + end + + # Allows overriding the +klass+ where the +copy_stream+ method is + # used to do efficient copying of regular files, pipes, and sockets. + # + # This is only used with multi-threaded concurrency models: + # + # * ThreadSpawn + # * ThreadPool + # * WriterThreadSpawn + # * WriterThreadPool + # * XEpollThreadSpawn + # * XEpollThreadPool + # + # Due to existing {bugs}[http://redmine.ruby-lang.org/search?q=copy_stream] + # in the Ruby IO.copy_stream implementation, \Rainbows! uses the + # "sendfile" RubyGem that instead of copy_stream to transfer regular files + # to clients. The "sendfile" RubyGem also supports more operating systems, + # and works with more concurrency models. + # + # Recent Linux 2.6 users may override this with "IO::Splice" from the + # "io_splice" RubyGem: + # + # require "io/splice" + # Rainbows! do + # copy_stream IO::Splice + # end + # + # Keep in mind that splice(2) itself is a relatively new system call + # and has been buggy in many older Linux kernels. + # + # Default: IO on Ruby 1.9+, false otherwise + def copy_stream(klass) + check! + if klass && ! klass.respond_to?(:copy_stream) + abort "#{klass} must respond to `copy_stream' or be `false'" + end + set[:copy_stream] = klass end end # :enddoc: # inject the Rainbows! method into Unicorn::Configurator