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