Module: Rainbows::Configurator

Defined in:
lib/rainbows/configurator.rb

Overview

This module adds Rainbows! to the Unicorn::Configurator Rainbows!-specific configuration options must be inside a the Rainbows! block, otherwise Unicorn::Configurator directives may be used anywhere in the file.

Warning: The “timeout” directive in unicorn is far more dangerous in Rainbows!, since ALL requests running on a process will be lost on worker death, not just one. Instead, handle application-level timeouts yourself: yhbt.net/unicorn/Application_Timeouts.html

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"

Instance Method Summary collapse

Instance Method Details

#check!Object

:nodoc:



53
54
55
# File 'lib/rainbows/configurator.rb', line 53

def check! # :nodoc:
  @block or abort "must be inside a Rainbows! block"
end

#client_header_buffer_size(bytes) ⇒ Object

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



179
180
181
182
# File 'lib/rainbows/configurator.rb', line 179

def client_header_buffer_size(bytes)
  check!
  set_int(:client_header_buffer_size, bytes, 1)
end

#client_max_body_size(bytes) ⇒ Object

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



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/rainbows/configurator.rb', line 143

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

#client_max_header_size(bytes) ⇒ Object

Limits the maximum size of a request header for all requests.

Default: 112 kilobytes (114688 bytes)

Lowering this will lower worst-case memory usage and mitigate some denial-of-service attacks. This should be larger than client_header_buffer_size.



163
164
165
166
# File 'lib/rainbows/configurator.rb', line 163

def client_max_header_size(bytes)
  check!
  set_int(:client_max_header_size, bytes, 8)
end

#copy_stream(klass) ⇒ Object

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 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. If you’re proxying the output of sockets to the client, be sure to use “io_splice” 4.1.1 or later to avoid stalling responses.

Default: IO on Ruby 1.9+, false otherwise



216
217
218
219
220
221
222
# File 'lib/rainbows/configurator.rb', line 216

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

#keepalive_requests(count) ⇒ Object

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.

Default: 100 requests



126
127
128
129
130
131
132
133
134
# File 'lib/rainbows/configurator.rb', line 126

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

#keepalive_timeout(seconds) ⇒ Object

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.

Setting this value to 0 disables keepalive entirely

Default: 5 seconds



114
115
116
117
# File 'lib/rainbows/configurator.rb', line 114

def keepalive_timeout(seconds)
  check!
  set_int(:keepalive_timeout, seconds, 0)
end

#Rainbows!(&block) ⇒ Object

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.



45
46
47
48
49
50
51
# File 'lib/rainbows/configurator.rb', line 45

def Rainbows!(&block)
  block_given? or raise ArgumentError, "Rainbows! requires a block"
  @block = true
  instance_eval(&block)
ensure
  @block = false
end

#use(model, *options) ⇒ Object

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
end

See the Summary document for a summary of supported concurrency models. options may be specified for some concurrency models, but the majority do not support them.

Default: :Base (no concurrency)



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rainbows/configurator.rb', line 82

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

#worker_connections(clients) ⇒ Object

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



64
65
66
67
# File 'lib/rainbows/configurator.rb', line 64

def worker_connections(clients)
  check!
  set_int(:worker_connections, clients, 1)
end