add "copy_stream" config directive
[rainbows.git] / lib / rainbows / configurator.rb
bloba1d90cb29239a7b1d8a72f11c12b0a4bac1e4b43
1 # -*- encoding: binary -*-
3 # This module adds \Rainbows! to the
4 # {Unicorn::Configurator}[http://unicorn.bogomips.org/Unicorn/Configurator.html]
5 # \Rainbows!-specific configuration options must be inside a the Rainbows!
6 # block, otherwise Unicorn::Configurator directives may be used anwwhere
7 # in the file.
9 #   Rainbows! do
10 #     use :ThreadSpawn # concurrency model to use
11 #     worker_connections 400
12 #     keepalive_timeout 0 # zero disables keepalives entirely
13 #     client_max_body_size 5*1024*1024 # 5 megabytes
14 #     keepalive_requests 666 # default:100
15 #     client_header_buffer_size 2 * 1024 # 2 kilobytes
16 #   end
18 #   # the rest of the Unicorn configuration...
19 #   worker_processes 8
20 #   stderr_path "/path/to/error.log"
21 #   stdout_path "/path/to/output.log"
22 module Rainbows::Configurator
23   Unicorn::Configurator::DEFAULTS.merge!({
24     :use => Rainbows::Base,
25     :worker_connections => 50,
26     :keepalive_timeout => 5,
27     :keepalive_requests => 100,
28     :client_max_body_size => 1024 * 1024,
29     :client_header_buffer_size => 1024,
30     :copy_stream => IO.respond_to?(:copy_stream) ? IO : false,
31   })
33   # Configures \Rainbows! with a given concurrency model to +use+ and
34   # a +worker_connections+ upper-bound.  This method should be called
35   # inside a Unicorn/\Rainbows! configuration file.
36   #
37   # All other methods in Rainbows::Configurator must be called
38   # inside this block.
39   def Rainbows!(&block)
40     block_given? or raise ArgumentError, "Rainbows! requires a block"
41     @block = true
42     instance_eval(&block)
43     ensure
44       @block = false
45   end
47   def check! # :nodoc:
48     @block or abort "must be inside a Rainbows! block"
49   end
51   # This limits the number of connected clients per-process.  The total
52   # number of clients on a server is +worker_processes+ * +worker_connections+.
53   #
54   # This option has no effect with the Base concurrency model, which is
55   # limited to +1+.
56   #
57   # Default: 50
58   def worker_connections(clients)
59     check!
60     set_int(:worker_connections, clients, 1)
61   end
63   # Select a concurrency model for use with \Rainbows!.  You must select
64   # this with a Symbol (prefixed with ":").  Thus if you wish to select
65   # the Rainbows::ThreadSpawn concurrency model, you would use:
66   #
67   #   Rainbows! do
68   #     use :ThreadSpawn
69   #   end
70   #
71   # See the {Summary}[link:Summary.html] document for a summary of
72   # supported concurrency models.  +options+ may be specified for some
73   # concurrency models, but the majority do not support them.
74   #
75   # Default: :Base (no concurrency)
76   def use(model, *options)
77     check!
78     mod = begin
79       Rainbows.const_get(model)
80     rescue NameError => e
81       warn "error loading #{model.inspect}: #{e}"
82       e.backtrace.each { |l| warn l }
83       abort "concurrency model #{model.inspect} not supported"
84     end
85     Module === mod or abort "concurrency model #{model.inspect} not supported"
86     options.each do |opt|
87       case opt
88       when Hash
89         Rainbows::O.merge!(opt)
90       when Symbol
91         Rainbows::O[opt] = true
92       else
93         abort "cannot handle option: #{opt.inspect} in #{options.inspect}"
94       end
95     end
96     mod.setup if mod.respond_to?(:setup)
97     set[:use] = mod
98   end
100   # Sets the value (in seconds) the server will wait for a client in
101   # between requests.  The default value should be enough under most
102   # conditions for browsers to render the page and start retrieving
103   # extra elements.
104   #
105   # Setting this value to +0+ disables keepalive entirely
106   #
107   # Default: 5 seconds
108   def keepalive_timeout(seconds)
109     check!
110     set_int(:keepalive_timeout, seconds, 0)
111   end
113   # This limits the number of requests which can be made over a keep-alive
114   # connection.  This is used to prevent single client from monopolizing
115   # the server and to improve fairness when load-balancing across multiple
116   # machines by forcing a client to reconnect.  This may be helpful
117   # in mitigating some denial-of-service attacks.
118   #
119   # Default: 100 requests
120   def keepalive_requests(count)
121     check!
122     case count
123     when nil, Integer
124       set[:keepalive_requests] = count
125     else
126       abort "not an integer or nil: keepalive_requests=#{count.inspect}"
127     end
128   end
130   # Limits the maximum size of a request body for all requests.
131   # Setting this to +nil+ disables the maximum size check.
132   #
133   # Default: 1 megabyte (1048576 bytes)
134   #
135   # If you want endpoint-specific upload limits and use a
136   # "rack.input"-streaming concurrency model, see the Rainbows::MaxBody
137   def client_max_body_size(bytes)
138     check!
139     err = "client_max_body_size must be nil or a non-negative Integer"
140     case bytes
141     when nil
142     when Integer
143       bytes >= 0 or abort err
144     else
145       abort err
146     end
147     set[:client_max_body_size] = bytes
148   end
150   # This governs the amount of memory allocated for an individual read(2) or
151   # recv(2) system call when reading headers.  Applications that make minimal
152   # use of cookies should not increase this from the default.
153   #
154   # Rails applications using session cookies may want to increase this to
155   # 2048 bytes or more depending on expected request sizes.
156   #
157   # Increasing this will increase overall memory usage to your application,
158   # as you will need at least this amount of memory for every connected client.
159   #
160   # Default: 1024 bytes
161   def client_header_buffer_size(bytes)
162     check!
163     set_int(:client_header_buffer_size, bytes, 1)
164   end
166   # Allows overriding the +klass+ where the +copy_stream+ method is
167   # used to do efficient copying of regular files, pipes, and sockets.
168   #
169   # This is only used with multi-threaded concurrency models:
170   #
171   # * ThreadSpawn
172   # * ThreadPool
173   # * WriterThreadSpawn
174   # * WriterThreadPool
175   # * XEpollThreadSpawn
176   # * XEpollThreadPool
177   #
178   # Due to existing {bugs}[http://redmine.ruby-lang.org/search?q=copy_stream]
179   # in the Ruby IO.copy_stream implementation, \Rainbows! uses the
180   # "sendfile" RubyGem that instead of copy_stream to transfer regular files
181   # to clients.  The "sendfile" RubyGem also supports more operating systems,
182   # and works with more concurrency models.
183   #
184   # Recent Linux 2.6 users may override this with "IO::Splice" from the
185   # "io_splice" RubyGem:
186   #
187   #   require "io/splice"
188   #   Rainbows! do
189   #     copy_stream IO::Splice
190   #   end
191   #
192   # Keep in mind that splice(2) itself is a relatively new system call
193   # and has been buggy in many older Linux kernels.
194   #
195   # Default: IO on Ruby 1.9+, false otherwise
196   def copy_stream(klass)
197     check!
198     if klass && ! klass.respond_to?(:copy_stream)
199       abort "#{klass} must respond to `copy_stream' or be `false'"
200     end
201     set[:copy_stream] = klass
202   end
205 # :enddoc:
206 # inject the Rainbows! method into Unicorn::Configurator
207 Unicorn::Configurator.__send__(:include, Rainbows::Configurator)