puma 3.9.1 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (82) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +232 -0
  3. data/README.md +162 -224
  4. data/docs/architecture.md +37 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +24 -4
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/plugins.md +38 -0
  10. data/docs/restart.md +41 -0
  11. data/docs/signals.md +56 -3
  12. data/docs/systemd.md +130 -37
  13. data/docs/tcp_mode.md +96 -0
  14. data/ext/puma_http11/PumaHttp11Service.java +2 -0
  15. data/ext/puma_http11/extconf.rb +13 -0
  16. data/ext/puma_http11/http11_parser.c +115 -140
  17. data/ext/puma_http11/http11_parser.java.rl +21 -37
  18. data/ext/puma_http11/http11_parser.rl +9 -9
  19. data/ext/puma_http11/http11_parser_common.rl +3 -3
  20. data/ext/puma_http11/mini_ssl.c +104 -8
  21. data/ext/puma_http11/org/jruby/puma/Http11.java +106 -114
  22. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +90 -108
  23. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
  24. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +21 -4
  25. data/ext/puma_http11/puma_http11.c +2 -0
  26. data/lib/puma.rb +16 -0
  27. data/lib/puma/accept_nonblock.rb +7 -1
  28. data/lib/puma/app/status.rb +40 -26
  29. data/lib/puma/binder.rb +57 -74
  30. data/lib/puma/cli.rb +26 -7
  31. data/lib/puma/client.rb +243 -190
  32. data/lib/puma/cluster.rb +78 -34
  33. data/lib/puma/commonlogger.rb +2 -0
  34. data/lib/puma/configuration.rb +24 -16
  35. data/lib/puma/const.rb +36 -18
  36. data/lib/puma/control_cli.rb +46 -19
  37. data/lib/puma/detect.rb +2 -0
  38. data/lib/puma/dsl.rb +329 -68
  39. data/lib/puma/events.rb +6 -1
  40. data/lib/puma/io_buffer.rb +3 -6
  41. data/lib/puma/jruby_restart.rb +2 -1
  42. data/lib/puma/launcher.rb +120 -58
  43. data/lib/puma/minissl.rb +69 -27
  44. data/lib/puma/minissl/context_builder.rb +76 -0
  45. data/lib/puma/null_io.rb +2 -0
  46. data/lib/puma/plugin.rb +7 -2
  47. data/lib/puma/plugin/tmp_restart.rb +2 -1
  48. data/lib/puma/rack/builder.rb +4 -1
  49. data/lib/puma/rack/urlmap.rb +2 -0
  50. data/lib/puma/rack_default.rb +2 -0
  51. data/lib/puma/reactor.rb +224 -34
  52. data/lib/puma/runner.rb +25 -4
  53. data/lib/puma/server.rb +148 -62
  54. data/lib/puma/single.rb +16 -5
  55. data/lib/puma/state_file.rb +2 -0
  56. data/lib/puma/tcp_logger.rb +2 -0
  57. data/lib/puma/thread_pool.rb +61 -38
  58. data/lib/puma/util.rb +2 -6
  59. data/lib/rack/handler/puma.rb +10 -4
  60. data/tools/docker/Dockerfile +16 -0
  61. data/tools/jungle/README.md +12 -2
  62. data/tools/jungle/init.d/README.md +2 -0
  63. data/tools/jungle/init.d/puma +8 -8
  64. data/tools/jungle/init.d/run-puma +1 -1
  65. data/tools/jungle/rc.d/README.md +74 -0
  66. data/tools/jungle/rc.d/puma +61 -0
  67. data/tools/jungle/rc.d/puma.conf +10 -0
  68. data/tools/trickletest.rb +1 -2
  69. metadata +29 -56
  70. data/.github/issue_template.md +0 -20
  71. data/Gemfile +0 -14
  72. data/Manifest.txt +0 -78
  73. data/Rakefile +0 -165
  74. data/Release.md +0 -9
  75. data/gemfiles/2.1-Gemfile +0 -12
  76. data/lib/puma/compat.rb +0 -14
  77. data/lib/puma/convenient.rb +0 -23
  78. data/lib/puma/daemon_ext.rb +0 -31
  79. data/lib/puma/delegation.rb +0 -11
  80. data/lib/puma/java_io_buffer.rb +0 -45
  81. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  82. data/puma.gemspec +0 -20
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
- require 'puma/state_file'
3
- require 'puma/const'
4
- require 'puma/detect'
5
- require 'puma/configuration'
4
+ require_relative 'state_file'
5
+ require_relative 'const'
6
+ require_relative 'detect'
7
+ require_relative 'configuration'
6
8
  require 'uri'
7
9
  require 'socket'
8
10
 
9
11
  module Puma
10
12
  class ControlCLI
11
13
 
12
- COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
14
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
13
15
 
14
16
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
15
17
  @state = nil
@@ -20,6 +22,7 @@ module Puma
20
22
  @control_auth_token = nil
21
23
  @config_file = nil
22
24
  @command = nil
25
+ @environment = ENV['RACK_ENV']
23
26
 
24
27
  @argv = argv.dup
25
28
  @stdout = stdout
@@ -57,6 +60,11 @@ module Puma
57
60
  @config_file = arg
58
61
  end
59
62
 
63
+ o.on "-e", "--environment ENVIRONMENT",
64
+ "The environment to run the Rack app on (default development)" do |arg|
65
+ @environment = arg
66
+ end
67
+
60
68
  o.on_tail("-H", "--help", "Show this message") do
61
69
  @stdout.puts o
62
70
  exit
@@ -69,12 +77,17 @@ module Puma
69
77
  end
70
78
 
71
79
  opts.order!(argv) { |a| opts.terminate a }
80
+ opts.parse!
72
81
 
73
82
  @command = argv.shift
74
83
 
75
84
  unless @config_file == '-'
76
- if @config_file.nil? and File.exist?('config/puma.rb')
77
- @config_file = 'config/puma.rb'
85
+ environment = @environment || 'development'
86
+
87
+ if @config_file.nil?
88
+ @config_file = %W(config/puma/#{environment}.rb config/puma.rb).find do |f|
89
+ File.exist?(f)
90
+ end
78
91
  end
79
92
 
80
93
  if @config_file
@@ -98,7 +111,6 @@ module Puma
98
111
 
99
112
  rescue => e
100
113
  @stdout.puts e.message
101
- @stdout.puts e.backtrace
102
114
  exit 1
103
115
  end
104
116
 
@@ -120,7 +132,7 @@ module Puma
120
132
  @pid = sf.pid
121
133
  elsif @pidfile
122
134
  # get pid from pid_file
123
- @pid = File.open(@pidfile).gets.to_i
135
+ File.open(@pidfile) { |f| @pid = f.read.to_i }
124
136
  end
125
137
  end
126
138
 
@@ -128,7 +140,13 @@ module Puma
128
140
  uri = URI.parse @control_url
129
141
 
130
142
  # create server object by scheme
131
- @server = case uri.scheme
143
+ server = case uri.scheme
144
+ when "ssl"
145
+ require 'openssl'
146
+ OpenSSL::SSL::SSLSocket.new(
147
+ TCPSocket.new(uri.host, uri.port),
148
+ OpenSSL::SSL::SSLContext.new
149
+ ).tap(&:connect)
132
150
  when "tcp"
133
151
  TCPSocket.new uri.host, uri.port
134
152
  when "unix"
@@ -146,9 +164,9 @@ module Puma
146
164
  url = url + "?token=#{@control_auth_token}"
147
165
  end
148
166
 
149
- @server << "GET #{url} HTTP/1.0\r\n\r\n"
167
+ server << "GET #{url} HTTP/1.0\r\n\r\n"
150
168
 
151
- unless data = @server.read
169
+ unless data = server.read
152
170
  raise "Server closed connection before responding"
153
171
  end
154
172
 
@@ -169,10 +187,10 @@ module Puma
169
187
  end
170
188
 
171
189
  message "Command #{@command} sent success"
172
- message response.last if @command == "stats"
190
+ message response.last if @command == "stats" || @command == "gc-stats"
173
191
  end
174
-
175
- @server.close
192
+ ensure
193
+ server.close if server && !server.closed?
176
194
  end
177
195
 
178
196
  def send_signal
@@ -203,8 +221,17 @@ module Puma
203
221
  when "phased-restart"
204
222
  Process.kill "SIGUSR1", @pid
205
223
 
224
+ when "status"
225
+ begin
226
+ Process.kill 0, @pid
227
+ puts "Puma is started"
228
+ rescue Errno::ESRCH
229
+ raise "Puma is not running"
230
+ end
231
+
232
+ return
233
+
206
234
  else
207
- message "Puma is started"
208
235
  return
209
236
  end
210
237
 
@@ -220,7 +247,7 @@ module Puma
220
247
  end
221
248
 
222
249
  def run
223
- start if @command == "start"
250
+ return start if @command == "start"
224
251
 
225
252
  prepare_configuration
226
253
 
@@ -232,7 +259,6 @@ module Puma
232
259
 
233
260
  rescue => e
234
261
  message e.message
235
- message e.backtrace
236
262
  exit 1
237
263
  end
238
264
 
@@ -245,9 +271,10 @@ module Puma
245
271
  run_args += ["-S", @state] if @state
246
272
  run_args += ["-q"] if @quiet
247
273
  run_args += ["--pidfile", @pidfile] if @pidfile
248
- run_args += ["--control", @control_url] if @control_url
274
+ run_args += ["--control-url", @control_url] if @control_url
249
275
  run_args += ["--control-token", @control_auth_token] if @control_auth_token
250
276
  run_args += ["-C", @config_file] if @config_file
277
+ run_args += ["-e", @environment] if @environment
251
278
 
252
279
  events = Puma::Events.new @stdout, @stderr
253
280
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  IS_JRUBY = defined?(JRUBY_VERSION)
3
5
 
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puma/const'
4
+
1
5
  module Puma
2
- # The methods that are available for use inside the config file.
6
+ # The methods that are available for use inside the configuration file.
3
7
  # These same methods are used in Puma cli and the rack handler
4
8
  # internally.
5
9
  #
@@ -24,7 +28,8 @@ module Puma
24
28
  # puts config.options[:binds]
25
29
  # # => "tcp://127.0.0.1:3002"
26
30
  #
27
- # Detailed docs can be found in `examples/config.rb`
31
+ # You can also find many examples being used by the test suite in
32
+ # +test/config+.
28
33
  class DSL
29
34
  include ConfigDefault
30
35
 
@@ -55,6 +60,14 @@ module Puma
55
60
  @plugins.clear
56
61
  end
57
62
 
63
+ def set_default_host(host)
64
+ @options[:default_host] = host
65
+ end
66
+
67
+ def default_host
68
+ @options[:default_host] || Configuration::DefaultTCPHost
69
+ end
70
+
58
71
  def inject(&blk)
59
72
  instance_eval(&blk)
60
73
  end
@@ -69,9 +82,22 @@ module Puma
69
82
  @plugins << @config.load_plugin(name)
70
83
  end
71
84
 
72
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
73
- # be the app itself.
85
+ # Use an object or block as the rack application. This allows the
86
+ # configuration file to be the application itself.
74
87
  #
88
+ # @example
89
+ # app do |env|
90
+ # body = 'Hello, World!'
91
+ #
92
+ # [
93
+ # 200,
94
+ # {
95
+ # 'Content-Type' => 'text/plain',
96
+ # 'Content-Length' => body.length.to_s
97
+ # },
98
+ # [body]
99
+ # ]
100
+ # end
75
101
  def app(obj=nil, &block)
76
102
  obj ||= block
77
103
 
@@ -80,9 +106,20 @@ module Puma
80
106
  @options[:app] = obj
81
107
  end
82
108
 
83
- # Start the Puma control rack app on +url+. This app can be communicated
84
- # with to control the main server.
109
+ # Start the Puma control rack application on +url+. This application can
110
+ # be communicated with to control the main server. Additionally, you can
111
+ # provide an authentication token, so all requests to the control server
112
+ # will need to include that token as a query parameter. This allows for
113
+ # simple authentication.
114
+ #
115
+ # Check out {Puma::App::Status} to see what the app has available.
85
116
  #
117
+ # @example
118
+ # activate_control_app 'unix:///var/run/pumactl.sock'
119
+ # @example
120
+ # activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
121
+ # @example
122
+ # activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
86
123
  def activate_control_app(url="auto", opts={})
87
124
  if url == "auto"
88
125
  path = Configuration.temp_path
@@ -93,7 +130,12 @@ module Puma
93
130
  end
94
131
 
95
132
  if opts[:no_token]
96
- auth_token = :none
133
+ # We need to use 'none' rather than :none because this value will be
134
+ # passed on to an instance of OptionParser, which doesn't support
135
+ # symbols as option values.
136
+ #
137
+ # See: https://github.com/puma/puma/issues/1193#issuecomment-305995488
138
+ auth_token = 'none'
97
139
  else
98
140
  auth_token = opts[:auth_token]
99
141
  auth_token ||= Configuration.random_token
@@ -110,50 +152,93 @@ module Puma
110
152
  @options[:config_files] << file
111
153
  end
112
154
 
113
- # Bind the server to +url+. tcp:// and unix:// are the only accepted
114
- # protocols.
155
+ # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
156
+ # accepted protocols. Multiple urls can be bound to, calling `bind` does
157
+ # not overwrite previous bindings.
115
158
  #
159
+ # The default is "tcp://0.0.0.0:9292".
160
+ #
161
+ # You can use query parameters within the url to specify options:
162
+ #
163
+ # - Set the socket backlog depth with +backlog+, default is 1024.
164
+ # - Set up an SSL certificate with +key+ & +cert+.
165
+ # - Set whether to optimize for low latency instead of throughput with
166
+ # +low_latency+, default is to optimize for low latency. This is done
167
+ # via +Socket::TCP_NODELAY+.
168
+ # - Set socket permissions with +umask+.
169
+ #
170
+ # @example Backlog depth
171
+ # bind 'unix:///var/run/puma.sock?backlog=512'
172
+ # @example SSL cert
173
+ # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
174
+ # @example Disable optimization for low latency
175
+ # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
+ # @example Socket permissions
177
+ # bind 'unix:///var/run/puma.sock?umask=0111'
116
178
  def bind(url)
117
179
  @options[:binds] ||= []
118
180
  @options[:binds] << url
119
181
  end
120
182
 
183
+ def clear_binds!
184
+ @options[:binds] = []
185
+ end
186
+
121
187
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
122
188
  #
189
+ # @example
190
+ # port 9292
123
191
  def port(port, host=nil)
124
- host ||= Configuration::DefaultTCPHost
192
+ host ||= default_host
125
193
  bind "tcp://#{host}:#{port}"
126
194
  end
127
195
 
128
- # Define how long persistent connections can be idle before puma closes
129
- # them
130
- #
196
+ # Define how long persistent connections can be idle before Puma closes
197
+ # them.
131
198
  def persistent_timeout(seconds)
132
- @options[:persistent_timeout] = seconds
199
+ @options[:persistent_timeout] = Integer(seconds)
200
+ end
201
+
202
+ # Define how long the tcp socket stays open, if no data has been received.
203
+ def first_data_timeout(seconds)
204
+ @options[:first_data_timeout] = Integer(seconds)
133
205
  end
134
206
 
135
207
  # Work around leaky apps that leave garbage in Thread locals
136
- # across requests
137
- #
208
+ # across requests.
138
209
  def clean_thread_locals(which=true)
139
210
  @options[:clean_thread_locals] = which
140
211
  end
141
212
 
142
- # Daemonize the server into the background. Highly suggest that
143
- # this be combined with +pidfile+ and +stdout_redirect+.
213
+ # Daemonize the server into the background. It's highly recommended to
214
+ # use this in combination with +pidfile+ and +stdout_redirect+.
215
+ #
216
+ # The default is "false".
217
+ #
218
+ # @example
219
+ # daemonize
220
+ #
221
+ # @example
222
+ # daemonize false
144
223
  def daemonize(which=true)
145
224
  @options[:daemon] = which
146
225
  end
147
226
 
148
227
  # When shutting down, drain the accept socket of pending
149
- # connections and proces them. This loops over the accept
228
+ # connections and process them. This loops over the accept
150
229
  # socket until there are no more read events and then stops
151
230
  # looking and waits for the requests to finish.
152
231
  def drain_on_shutdown(which=true)
153
232
  @options[:drain_on_shutdown] = which
154
233
  end
155
234
 
156
- # Set the environment in which the Rack's app will run.
235
+ # Set the environment in which the rack's app will run. The value must be
236
+ # a string.
237
+ #
238
+ # The default is "development".
239
+ #
240
+ # @example
241
+ # environment 'production'
157
242
  def environment(environment)
158
243
  @options[:environment] = environment
159
244
  end
@@ -179,30 +264,41 @@ module Puma
179
264
  end
180
265
 
181
266
  # Code to run before doing a restart. This code should
182
- # close logfiles, database connections, etc.
267
+ # close log files, database connections, etc.
183
268
  #
184
269
  # This can be called multiple times to add code each time.
185
270
  #
271
+ # @example
272
+ # on_restart do
273
+ # puts 'On restart...'
274
+ # end
186
275
  def on_restart(&block)
187
276
  @options[:on_restart] ||= []
188
277
  @options[:on_restart] << block
189
278
  end
190
279
 
191
- # Command to use to restart puma. This should be just how to
192
- # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
193
- # to puma, as those are the same as the original process.
280
+ # Command to use to restart Puma. This should be just how to
281
+ # load Puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
282
+ # to Puma, as those are the same as the original process.
194
283
  #
284
+ # @example
285
+ # restart_command '/u/app/lolcat/bin/restart_puma'
195
286
  def restart_command(cmd)
196
287
  @options[:restart_cmd] = cmd.to_s
197
288
  end
198
289
 
199
- # Store the pid of the server in the file at +path+.
290
+ # Store the pid of the server in the file at "path".
291
+ #
292
+ # @example
293
+ # pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
200
294
  def pidfile(path)
201
295
  @options[:pidfile] = path.to_s
202
296
  end
203
297
 
204
- # Disable request logging.
298
+ # Disable request logging, if this isn't used it'll be enabled by default.
205
299
  #
300
+ # @example
301
+ # quiet
206
302
  def quiet(which=true)
207
303
  @options[:log_requests] = !which
208
304
  end
@@ -221,6 +317,10 @@ module Puma
221
317
 
222
318
  # Load +path+ as a rackup file.
223
319
  #
320
+ # The default is "config.ru".
321
+ #
322
+ # @example
323
+ # rackup '/u/apps/lolcat/config.ru'
224
324
  def rackup(path)
225
325
  @options[:rackup] = path.to_s
226
326
  end
@@ -231,16 +331,36 @@ module Puma
231
331
  @options[:mode] = :tcp
232
332
  end
233
333
 
234
- # Redirect STDOUT and STDERR to files specified.
334
+ def early_hints(answer=true)
335
+ @options[:early_hints] = answer
336
+ end
337
+
338
+ # Redirect STDOUT and STDERR to files specified. The +append+ parameter
339
+ # specifies whether the output is appended, the default is +false+.
340
+ #
341
+ # @example
342
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr'
343
+ # @example
344
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr', true
235
345
  def stdout_redirect(stdout=nil, stderr=nil, append=false)
236
346
  @options[:redirect_stdout] = stdout
237
347
  @options[:redirect_stderr] = stderr
238
348
  @options[:redirect_append] = append
239
349
  end
240
350
 
351
+ def log_formatter(&block)
352
+ @options[:log_formatter] = block
353
+ end
354
+
241
355
  # Configure +min+ to be the minimum number of threads to use to answer
242
356
  # requests and +max+ the maximum.
243
357
  #
358
+ # The default is "0, 16".
359
+ #
360
+ # @example
361
+ # threads 0, 16
362
+ # @example
363
+ # threads 5, 5
244
364
  def threads(min, max)
245
365
  min = Integer(min)
246
366
  max = Integer(max)
@@ -256,81 +376,135 @@ module Puma
256
376
  @options[:max_threads] = max
257
377
  end
258
378
 
379
+ # Instead of "bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'" you
380
+ # can also use the "ssl_bind" option.
381
+ #
382
+ # @example
383
+ # ssl_bind '127.0.0.1', '9292', {
384
+ # cert: path_to_cert,
385
+ # key: path_to_key,
386
+ # ssl_cipher_filter: cipher_filter, # optional
387
+ # verify_mode: verify_mode, # default 'none'
388
+ # }
389
+ # @example For JRuby additional keys are required: keystore & keystore_pass.
390
+ # ssl_bind '127.0.0.1', '9292', {
391
+ # cert: path_to_cert,
392
+ # key: path_to_key,
393
+ # ssl_cipher_filter: cipher_filter, # optional
394
+ # verify_mode: verify_mode, # default 'none'
395
+ # keystore: path_to_keystore,
396
+ # keystore_pass: password
397
+ # }
259
398
  def ssl_bind(host, port, opts)
260
- verify = opts.fetch(:verify_mode, 'none')
399
+ verify = opts.fetch(:verify_mode, 'none').to_s
400
+ no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
401
+ no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
402
+ ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
261
403
 
262
404
  if defined?(JRUBY_VERSION)
263
405
  keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
264
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}"
406
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
265
407
  else
266
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&verify_mode=#{verify}"
408
+ ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
409
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
267
410
  end
268
411
  end
269
412
 
270
413
  # Use +path+ as the file to store the server info state. This is
271
- # used by pumactl to query and control the server.
414
+ # used by +pumactl+ to query and control the server.
272
415
  #
416
+ # @example
417
+ # state_path '/u/apps/lolcat/tmp/pids/puma.state'
273
418
  def state_path(path)
274
419
  @options[:state] = path.to_s
275
420
  end
276
421
 
277
- # *Cluster mode only* How many worker processes to run.
422
+ # How many worker processes to run. Typically this is set to
423
+ # to the number of available cores.
424
+ #
425
+ # The default is 0.
278
426
  #
427
+ # @note Cluster mode only.
279
428
  def workers(count)
280
429
  @options[:workers] = count.to_i
281
430
  end
282
431
 
283
- # *Cluster mode only* Code to run immediately before master process
432
+ # Code to run immediately before master process
284
433
  # forks workers (once on boot). These hooks can block if necessary
285
- # to wait for background operations unknown to puma to finish before
434
+ # to wait for background operations unknown to Puma to finish before
286
435
  # the process terminates.
287
- # This can be used to close any connections to remote servers (database, redis, ...)
288
- # that were opened when preloading the code
436
+ # This can be used to close any connections to remote servers (database,
437
+ # Redis, ...) that were opened when preloading the code.
289
438
  #
290
- # This can be called multiple times to add hooks.
439
+ # This can be called multiple times to add several hooks.
291
440
  #
441
+ # @note Cluster mode only.
442
+ # @example
443
+ # before_fork do
444
+ # puts "Starting workers..."
445
+ # end
292
446
  def before_fork(&block)
293
447
  @options[:before_fork] ||= []
294
448
  @options[:before_fork] << block
295
449
  end
296
450
 
297
- # *Cluster mode only* Code to run in a worker when it boots to setup
451
+ # Code to run in a worker when it boots to setup
298
452
  # the process before booting the app.
299
453
  #
300
- # This can be called multiple times to add hooks.
454
+ # This can be called multiple times to add several hooks.
301
455
  #
456
+ # @note Cluster mode only.
457
+ # @example
458
+ # on_worker_fork do
459
+ # puts 'Before worker fork...'
460
+ # end
302
461
  def on_worker_boot(&block)
303
462
  @options[:before_worker_boot] ||= []
304
463
  @options[:before_worker_boot] << block
305
464
  end
306
465
 
307
- # *Cluster mode only* Code to run immediately before a worker shuts
466
+ # Code to run immediately before a worker shuts
308
467
  # down (after it has finished processing HTTP requests). These hooks
309
468
  # can block if necessary to wait for background operations unknown
310
- # to puma to finish before the process terminates.
469
+ # to Puma to finish before the process terminates.
311
470
  #
312
- # This can be called multiple times to add hooks.
471
+ # This can be called multiple times to add several hooks.
313
472
  #
473
+ # @note Cluster mode only.
474
+ # @example
475
+ # on_worker_shutdown do
476
+ # puts 'On worker shutdown...'
477
+ # end
314
478
  def on_worker_shutdown(&block)
315
479
  @options[:before_worker_shutdown] ||= []
316
480
  @options[:before_worker_shutdown] << block
317
481
  end
318
482
 
319
- # *Cluster mode only* Code to run in the master when it is
320
- # about to create the worker by forking itself.
483
+ # Code to run in the master right before a worker is started. The worker's
484
+ # index is passed as an argument.
321
485
  #
322
- # This can be called multiple times to add hooks.
486
+ # This can be called multiple times to add several hooks.
323
487
  #
488
+ # @note Cluster mode only.
489
+ # @example
490
+ # on_worker_fork do
491
+ # puts 'Before worker fork...'
492
+ # end
324
493
  def on_worker_fork(&block)
325
494
  @options[:before_worker_fork] ||= []
326
495
  @options[:before_worker_fork] << block
327
496
  end
328
497
 
329
- # *Cluster mode only* Code to run in the master after it starts
330
- # a worker.
498
+ # Code to run in the master after a worker has been started. The worker's
499
+ # index is passed as an argument.
331
500
  #
332
- # This can be called multiple times to add hooks.
501
+ # This is called everytime a worker is to be started.
333
502
  #
503
+ # @note Cluster mode only.
504
+ # @example
505
+ # after_worker_fork do
506
+ # puts 'After worker fork...'
507
+ # end
334
508
  def after_worker_fork(&block)
335
509
  @options[:after_worker_fork] ||= []
336
510
  @options[:after_worker_fork] = block
@@ -338,7 +512,26 @@ module Puma
338
512
 
339
513
  alias_method :after_worker_boot, :after_worker_fork
340
514
 
515
+ # Code to run out-of-band when the worker is idle.
516
+ # These hooks run immediately after a request has finished
517
+ # processing and there are no busy threads on the worker.
518
+ # The worker doesn't accept new requests until this code finishes.
519
+ #
520
+ # This hook is useful for running out-of-band garbage collection
521
+ # or scheduling asynchronous tasks to execute after a response.
522
+ #
523
+ # This can be called multiple times to add several hooks.
524
+ def out_of_band(&block)
525
+ @options[:out_of_band] ||= []
526
+ @options[:out_of_band] << block
527
+ end
528
+
341
529
  # The directory to operate out of.
530
+ #
531
+ # The default is the current directory.
532
+ #
533
+ # @example
534
+ # directory '/u/apps/lolcat'
342
535
  def directory(dir)
343
536
  @options[:directory] = dir.to_s
344
537
  end
@@ -349,22 +542,28 @@ module Puma
349
542
  directory dir
350
543
  end
351
544
 
352
- # Run the app as a raw TCP app instead of an HTTP rack app
545
+ # Run the app as a raw TCP app instead of an HTTP rack app.
353
546
  def tcp_mode
354
547
  @options[:mode] = :tcp
355
548
  end
356
549
 
357
- # *Cluster mode only* Preload the application before starting
358
- # the workers and setting up the listen ports. This conflicts
359
- # with using the phased restart feature, you can't use both.
550
+ # Preload the application before starting the workers; this conflicts with
551
+ # phased restart feature. This is off by default.
360
552
  #
553
+ # @note Cluster mode only.
554
+ # @example
555
+ # preload_app!
361
556
  def preload_app!(answer=true)
362
557
  @options[:preload_app] = answer
363
558
  end
364
559
 
365
- # Use +obj+ or +block+ as the low level error handler. This allows a config file to
366
- # change the default error on the server.
560
+ # Use +obj+ or +block+ as the low level error handler. This allows the
561
+ # configuration file to change the default error on the server.
367
562
  #
563
+ # @example
564
+ # lowlevel_error_handler do |err|
565
+ # [200, {}, ["error page"]]
566
+ # end
368
567
  def lowlevel_error_handler(obj=nil, &block)
369
568
  obj ||= block
370
569
  raise "Provide either a #call'able or a block" unless obj
@@ -374,40 +573,102 @@ module Puma
374
573
  # This option is used to allow your app and its gems to be
375
574
  # properly reloaded when not using preload.
376
575
  #
377
- # When set, if puma detects that it's been invoked in the
576
+ # When set, if Puma detects that it's been invoked in the
378
577
  # context of Bundler, it will cleanup the environment and
379
578
  # re-run itself outside the Bundler environment, but directly
380
579
  # using the files that Bundler has setup.
381
580
  #
382
- # This means that puma is now decoupled from your Bundler
581
+ # This means that Puma is now decoupled from your Bundler
383
582
  # context and when each worker loads, it will be loading a
384
583
  # new Bundler context and thus can float around as the release
385
584
  # dictates.
585
+ #
586
+ # See also: extra_runtime_dependencies
587
+ #
588
+ # @note This is incompatible with +preload_app!+.
589
+ # @note This is only supported for RubyGems 2.2+
386
590
  def prune_bundler(answer=true)
387
591
  @options[:prune_bundler] = answer
388
592
  end
389
593
 
390
- # Additional text to display in process listing
594
+ # By default, Puma will raise SignalException when SIGTERM is received. In
595
+ # environments where SIGTERM is something expected, you can suppress these
596
+ # with this option.
597
+ #
598
+ # This can be useful for example in Kubernetes, where rolling restart is
599
+ # guaranteed usually on infrastructure level.
600
+ #
601
+ # @example
602
+ # raise_exception_on_sigterm false
603
+ def raise_exception_on_sigterm(answer=true)
604
+ @options[:raise_exception_on_sigterm] = answer
605
+ end
606
+
607
+ # When using prune_bundler, if extra runtime dependencies need to be loaded to
608
+ # initialize your app, then this setting can be used. This includes any Puma plugins.
609
+ #
610
+ # Before bundler is pruned, the gem names supplied will be looked up in the bundler
611
+ # context and then loaded again after bundler is pruned.
612
+ # Only applies if prune_bundler is used.
613
+ #
614
+ # @example
615
+ # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
616
+ # @example
617
+ # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
618
+ def extra_runtime_dependencies(answer = [])
619
+ @options[:extra_runtime_dependencies] = Array(answer)
620
+ end
621
+
622
+ # Additional text to display in process listing.
623
+ #
624
+ # If you do not specify a tag, Puma will infer it. If you do not want Puma
625
+ # to add a tag, use an empty string.
626
+ #
627
+ # @example
628
+ # tag 'app name'
629
+ # @example
630
+ # tag ''
391
631
  def tag(string)
392
632
  @options[:tag] = string.to_s
393
633
  end
394
634
 
395
- # *Cluster mode only* Set the timeout for workers in seconds
396
- # When set the master process will terminate any workers
397
- # that have not checked in within the given +timeout+.
398
- # This mitigates hung processes. Default value is 60 seconds.
635
+ # Verifies that all workers have checked in to the master process within
636
+ # the given timeout. If not the worker process will be restarted. This is
637
+ # not a request timeout, it is to protect against a hung or dead process.
638
+ # Setting this value will not protect against slow requests.
639
+ #
640
+ # The minimum value is 6 seconds, the default value is 60 seconds.
641
+ #
642
+ # @note Cluster mode only.
643
+ # @example
644
+ # worker_timeout 60
399
645
  def worker_timeout(timeout)
646
+ timeout = Integer(timeout)
647
+ min = Const::WORKER_CHECK_INTERVAL
648
+
649
+ if timeout <= min
650
+ raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
651
+ end
652
+
400
653
  @options[:worker_timeout] = timeout
401
654
  end
402
655
 
403
- # *Cluster mode only* Set the timeout for workers to boot
656
+ # Change the default worker timeout for booting.
657
+ #
658
+ # If unspecified, this defaults to the value of worker_timeout.
659
+ #
660
+ # @note Cluster mode only.
661
+ # @example:
662
+ # worker_boot_timeout 60
404
663
  def worker_boot_timeout(timeout)
405
- @options[:worker_boot_timeout] = timeout
664
+ @options[:worker_boot_timeout] = Integer(timeout)
406
665
  end
407
666
 
408
- # *Cluster mode only* Set the timeout for worker shutdown
667
+ # Set the timeout for worker shutdown
668
+ #
669
+ # @note Cluster mode only.
409
670
  def worker_shutdown_timeout(timeout)
410
- @options[:worker_shutdown_timeout] = timeout
671
+ @options[:worker_shutdown_timeout] = Integer(timeout)
411
672
  end
412
673
 
413
674
  # When set to true (the default), workers accept all requests
@@ -422,7 +683,7 @@ module Puma
422
683
  # Note that setting this to false disables HTTP keepalive and
423
684
  # slow clients will occupy a handler thread while the request
424
685
  # is being sent. A reverse proxy, such as nginx, can handle
425
- # slow clients and queue requests before they reach puma.
686
+ # slow clients and queue requests before they reach Puma.
426
687
  def queue_requests(answer=true)
427
688
  @options[:queue_requests] = answer
428
689
  end
@@ -451,7 +712,7 @@ module Puma
451
712
  # is used, allowing headers such as X-Forwarded-For
452
713
  # to be used as well.
453
714
  # * Any string - this allows you to hardcode remote address to any value
454
- # you wish. Because puma never uses this field anyway, it's
715
+ # you wish. Because Puma never uses this field anyway, it's
455
716
  # format is entirely in your hands.
456
717
  def set_remote_address(val=:socket)
457
718
  case val
@@ -466,7 +727,7 @@ module Puma
466
727
  when Hash
467
728
  if hdr = val[:header]
468
729
  @options[:remote_address] = :header
469
- @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
730
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
470
731
  else
471
732
  raise "Invalid value for set_remote_address - #{val.inspect}"
472
733
  end