puma 3.12.1 → 4.1.0

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.

data/lib/puma/cluster.rb CHANGED
@@ -19,8 +19,6 @@ module Puma
19
19
  # via the `spawn_workers` method call. Each worker will have it's own
20
20
  # instance of a `Puma::Server`.
21
21
  class Cluster < Runner
22
- WORKER_CHECK_INTERVAL = 5
23
-
24
22
  def initialize(cli, events)
25
23
  super cli, events
26
24
 
@@ -37,7 +35,35 @@ module Puma
37
35
  @workers.each { |x| x.term }
38
36
 
39
37
  begin
40
- @workers.each { |w| Process.waitpid(w.pid) }
38
+ if RUBY_VERSION < '2.6'
39
+ @workers.each do |w|
40
+ begin
41
+ Process.waitpid(w.pid)
42
+ rescue Errno::ECHILD
43
+ # child is already terminated
44
+ end
45
+ end
46
+ else
47
+ # below code is for a bug in Ruby 2.6+, above waitpid call hangs
48
+ t_st = Process.clock_gettime(Process::CLOCK_MONOTONIC)
49
+ pids = @workers.map(&:pid)
50
+ loop do
51
+ pids.reject! do |w_pid|
52
+ begin
53
+ if Process.waitpid(w_pid, Process::WNOHANG)
54
+ log " worker status: #{$?}"
55
+ true
56
+ end
57
+ rescue Errno::ECHILD
58
+ true # child is already terminated
59
+ end
60
+ end
61
+ break if pids.empty?
62
+ sleep 0.5
63
+ end
64
+ t_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
65
+ log format(" worker shutdown time: %6.2f", t_end - t_st)
66
+ end
41
67
  rescue Interrupt
42
68
  log "! Cancelled waiting for workers"
43
69
  end
@@ -69,12 +95,13 @@ module Puma
69
95
  @signal = "TERM"
70
96
  @options = options
71
97
  @first_term_sent = nil
98
+ @started_at = Time.now
72
99
  @last_checkin = Time.now
73
100
  @last_status = '{}'
74
101
  @dead = false
75
102
  end
76
103
 
77
- attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status
104
+ attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
78
105
 
79
106
  def booted?
80
107
  @stage == :booted
@@ -183,7 +210,7 @@ module Puma
183
210
  def check_workers(force=false)
184
211
  return if !force && @next_check && @next_check >= Time.now
185
212
 
186
- @next_check = Time.now + WORKER_CHECK_INTERVAL
213
+ @next_check = Time.now + Const::WORKER_CHECK_INTERVAL
187
214
 
188
215
  any = false
189
216
 
@@ -200,14 +227,11 @@ module Puma
200
227
  # during this loop by giving the kernel time to kill them.
201
228
  sleep 1 if any
202
229
 
203
- while @workers.any?
204
- pid = Process.waitpid(-1, Process::WNOHANG)
205
- break unless pid
206
-
207
- @workers.delete_if { |w| w.pid == pid }
230
+ pids = []
231
+ while pid = Process.waitpid(-1, Process::WNOHANG) do
232
+ pids << pid
208
233
  end
209
-
210
- @workers.delete_if(&:dead?)
234
+ @workers.reject! { |w| w.dead? || pids.include?(w.pid) }
211
235
 
212
236
  cull_workers
213
237
  spawn_workers
@@ -290,7 +314,7 @@ module Puma
290
314
  base_payload = "p#{Process.pid}"
291
315
 
292
316
  while true
293
- sleep WORKER_CHECK_INTERVAL
317
+ sleep Const::WORKER_CHECK_INTERVAL
294
318
  begin
295
319
  b = server.backlog || 0
296
320
  r = server.running || 0
@@ -355,8 +379,8 @@ module Puma
355
379
  def stats
356
380
  old_worker_count = @workers.count { |w| w.phase != @phase }
357
381
  booted_worker_count = @workers.count { |w| w.booted? }
358
- worker_status = '[' + @workers.map { |w| %Q!{ "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
359
- %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
382
+ worker_status = '[' + @workers.map { |w| %Q!{ "started_at": "#{w.started_at.utc.iso8601}", "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
383
+ %Q!{ "started_at": "#{@started_at.utc.iso8601}", "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
360
384
  end
361
385
 
362
386
  def preload?
@@ -390,10 +414,13 @@ module Puma
390
414
  log "Early termination of worker"
391
415
  exit! 0
392
416
  else
417
+ @launcher.close_binder_listeners
418
+
393
419
  stop_workers
394
420
  stop
395
421
 
396
- raise SignalException, "SIGTERM"
422
+ raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
423
+ exit 0 # Clean exit, workers were stopped
397
424
  end
398
425
  end
399
426
  end
@@ -487,7 +514,7 @@ module Puma
487
514
 
488
515
  force_check = false
489
516
 
490
- res = IO.select([read], nil, nil, WORKER_CHECK_INTERVAL)
517
+ res = IO.select([read], nil, nil, Const::WORKER_CHECK_INTERVAL)
491
518
 
492
519
  if res
493
520
  req = read.read_nonblock(1)
@@ -20,7 +20,7 @@ module Puma
20
20
  # In this class any "user" specified options take precedence over any
21
21
  # "file" specified options, take precedence over any "default" options.
22
22
  #
23
- # User input is prefered over "defaults":
23
+ # User input is preferred over "defaults":
24
24
  # user_options = { foo: "bar" }
25
25
  # default_options = { foo: "zoo" }
26
26
  # options = UserFileDefaultOptions.new(user_options, default_options)
@@ -32,7 +32,7 @@ module Puma
32
32
  # puts options.all_of(:foo)
33
33
  # # => ["bar", "zoo"]
34
34
  #
35
- # A "file" option can be set. This config will be prefered over "default" options
35
+ # A "file" option can be set. This config will be preferred over "default" options
36
36
  # but will defer to any available "user" specified options.
37
37
  #
38
38
  # user_options = { foo: "bar" }
@@ -186,7 +186,8 @@ module Puma
186
186
  :rackup => DefaultRackup,
187
187
  :logger => STDOUT,
188
188
  :persistent_timeout => Const::PERSISTENT_TIMEOUT,
189
- :first_data_timeout => Const::FIRST_DATA_TIMEOUT
189
+ :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
190
+ :raise_exception_on_sigterm => true
190
191
  }
191
192
  end
192
193
 
data/lib/puma/const.rb CHANGED
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "3.12.1".freeze
104
- CODE_NAME = "Llamas in Pajamas".freeze
103
+ PUMA_VERSION = VERSION = "4.1.0".freeze
104
+ CODE_NAME = "Fourth and One".freeze
105
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
106
 
107
107
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -160,6 +160,9 @@ module Puma
160
160
  LINE_END = "\r\n".freeze
161
161
  REMOTE_ADDR = "REMOTE_ADDR".freeze
162
162
  HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
163
+ HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
164
+ HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
165
+ HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
163
166
 
164
167
  SERVER_NAME = "SERVER_NAME".freeze
165
168
  SERVER_PORT = "SERVER_PORT".freeze
@@ -227,5 +230,9 @@ module Puma
227
230
  HIJACK_IO = "rack.hijack_io".freeze
228
231
 
229
232
  EARLY_HINTS = "rack.early_hints".freeze
233
+
234
+ # Mininum interval to checks worker health
235
+ WORKER_CHECK_INTERVAL = 5
236
+
230
237
  end
231
238
  end
@@ -101,7 +101,6 @@ module Puma
101
101
 
102
102
  rescue => e
103
103
  @stdout.puts e.message
104
- @stdout.puts e.backtrace
105
104
  exit 1
106
105
  end
107
106
 
@@ -206,6 +205,16 @@ module Puma
206
205
  when "phased-restart"
207
206
  Process.kill "SIGUSR1", @pid
208
207
 
208
+ when "status"
209
+ begin
210
+ Process.kill 0, @pid
211
+ puts "Puma is started"
212
+ rescue Errno::ESRCH
213
+ raise "Puma is not running"
214
+ end
215
+
216
+ return
217
+
209
218
  else
210
219
  return
211
220
  end
@@ -234,7 +243,6 @@ module Puma
234
243
 
235
244
  rescue => e
236
245
  message e.message
237
- message e.backtrace
238
246
  exit 1
239
247
  end
240
248
 
data/lib/puma/dsl.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'puma/const'
4
+
3
5
  module Puma
4
- # The methods that are available for use inside the config file.
6
+ # The methods that are available for use inside the configuration file.
5
7
  # These same methods are used in Puma cli and the rack handler
6
8
  # internally.
7
9
  #
@@ -26,7 +28,8 @@ module Puma
26
28
  # puts config.options[:binds]
27
29
  # # => "tcp://127.0.0.1:3002"
28
30
  #
29
- # 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+.
30
33
  class DSL
31
34
  include ConfigDefault
32
35
 
@@ -79,9 +82,22 @@ module Puma
79
82
  @plugins << @config.load_plugin(name)
80
83
  end
81
84
 
82
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
83
- # 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.
87
+ #
88
+ # @example
89
+ # app do |env|
90
+ # body = 'Hello, World!'
84
91
  #
92
+ # [
93
+ # 200,
94
+ # {
95
+ # 'Content-Type' => 'text/plain',
96
+ # 'Content-Length' => body.length.to_s
97
+ # },
98
+ # [body]
99
+ # ]
100
+ # end
85
101
  def app(obj=nil, &block)
86
102
  obj ||= block
87
103
 
@@ -90,9 +106,20 @@ module Puma
90
106
  @options[:app] = obj
91
107
  end
92
108
 
93
- # Start the Puma control rack app on +url+. This app can be communicated
94
- # 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.
95
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 }
96
123
  def activate_control_app(url="auto", opts={})
97
124
  if url == "auto"
98
125
  path = Configuration.temp_path
@@ -103,7 +130,12 @@ module Puma
103
130
  end
104
131
 
105
132
  if opts[:no_token]
106
- 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'
107
139
  else
108
140
  auth_token = opts[:auth_token]
109
141
  auth_token ||= Configuration.random_token
@@ -120,22 +152,29 @@ module Puma
120
152
  @options[:config_files] << file
121
153
  end
122
154
 
123
- # Adds a binding for the server to +url+. tcp://, unix://, and ssl:// are the only accepted
124
- # protocols. Use query parameters within the url to specify options.
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.
125
158
  #
126
- # @note multiple urls can be bound to, calling `bind` does not overwrite previous bindings.
159
+ # The default is "tcp://0.0.0.0:9292".
127
160
  #
128
- # @example Explicitly the socket backlog depth (default is 1024)
129
- # bind('unix:///var/run/puma.sock?backlog=2048')
161
+ # You can use query parameters within the url to specify options:
130
162
  #
131
- # @example Set up ssl cert
132
- # bind('ssl://127.0.0.1:9292?key=key.key&cert=cert.pem')
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+.
133
169
  #
134
- # @example Prefer low-latency over higher throughput (via `Socket::TCP_NODELAY`)
135
- # bind('tcp://0.0.0.0:9292?low_latency=true')
136
- #
137
- # @example Set socket permissions
138
- # bind('unix:///var/run/puma.sock?umask=0111')
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'
139
178
  def bind(url)
140
179
  @options[:binds] ||= []
141
180
  @options[:binds] << url
@@ -147,33 +186,40 @@ module Puma
147
186
 
148
187
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
149
188
  #
189
+ # @example
190
+ # port 9292
150
191
  def port(port, host=nil)
151
192
  host ||= default_host
152
193
  bind "tcp://#{host}:#{port}"
153
194
  end
154
195
 
155
- # Define how long persistent connections can be idle before puma closes
156
- # them
157
- #
196
+ # Define how long persistent connections can be idle before Puma closes
197
+ # them.
158
198
  def persistent_timeout(seconds)
159
199
  @options[:persistent_timeout] = Integer(seconds)
160
200
  end
161
201
 
162
- # Define how long the tcp socket stays open, if no data has been received
163
- #
202
+ # Define how long the tcp socket stays open, if no data has been received.
164
203
  def first_data_timeout(seconds)
165
204
  @options[:first_data_timeout] = Integer(seconds)
166
205
  end
167
206
 
168
207
  # Work around leaky apps that leave garbage in Thread locals
169
- # across requests
170
- #
208
+ # across requests.
171
209
  def clean_thread_locals(which=true)
172
210
  @options[:clean_thread_locals] = which
173
211
  end
174
212
 
175
- # Daemonize the server into the background. Highly suggest that
176
- # 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
177
223
  def daemonize(which=true)
178
224
  @options[:daemon] = which
179
225
  end
@@ -186,7 +232,13 @@ module Puma
186
232
  @options[:drain_on_shutdown] = which
187
233
  end
188
234
 
189
- # 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'
190
242
  def environment(environment)
191
243
  @options[:environment] = environment
192
244
  end
@@ -212,30 +264,41 @@ module Puma
212
264
  end
213
265
 
214
266
  # Code to run before doing a restart. This code should
215
- # close logfiles, database connections, etc.
267
+ # close log files, database connections, etc.
216
268
  #
217
269
  # This can be called multiple times to add code each time.
218
270
  #
271
+ # @example
272
+ # on_restart do
273
+ # puts 'On restart...'
274
+ # end
219
275
  def on_restart(&block)
220
276
  @options[:on_restart] ||= []
221
277
  @options[:on_restart] << block
222
278
  end
223
279
 
224
- # Command to use to restart puma. This should be just how to
225
- # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
226
- # 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.
227
283
  #
284
+ # @example
285
+ # restart_command '/u/app/lolcat/bin/restart_puma'
228
286
  def restart_command(cmd)
229
287
  @options[:restart_cmd] = cmd.to_s
230
288
  end
231
289
 
232
- # 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'
233
294
  def pidfile(path)
234
295
  @options[:pidfile] = path.to_s
235
296
  end
236
297
 
237
- # Disable request logging.
298
+ # Disable request logging, if this isn't used it'll be enabled by default.
238
299
  #
300
+ # @example
301
+ # quiet
239
302
  def quiet(which=true)
240
303
  @options[:log_requests] = !which
241
304
  end
@@ -254,6 +317,10 @@ module Puma
254
317
 
255
318
  # Load +path+ as a rackup file.
256
319
  #
320
+ # The default is "config.ru".
321
+ #
322
+ # @example
323
+ # rackup '/u/apps/lolcat/config.ru'
257
324
  def rackup(path)
258
325
  @options[:rackup] = path.to_s
259
326
  end
@@ -268,16 +335,32 @@ module Puma
268
335
  @options[:early_hints] = answer
269
336
  end
270
337
 
271
- # Redirect STDOUT and STDERR to files specified.
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
272
345
  def stdout_redirect(stdout=nil, stderr=nil, append=false)
273
346
  @options[:redirect_stdout] = stdout
274
347
  @options[:redirect_stderr] = stderr
275
348
  @options[:redirect_append] = append
276
349
  end
277
350
 
351
+ def log_formatter(&block)
352
+ @options[:log_formatter] = block
353
+ end
354
+
278
355
  # Configure +min+ to be the minimum number of threads to use to answer
279
356
  # requests and +max+ the maximum.
280
357
  #
358
+ # The default is "0, 16".
359
+ #
360
+ # @example
361
+ # threads 0, 16
362
+ # @example
363
+ # threads 5, 5
281
364
  def threads(min, max)
282
365
  min = Integer(min)
283
366
  max = Integer(max)
@@ -293,81 +376,135 @@ module Puma
293
376
  @options[:max_threads] = max
294
377
  end
295
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
+ # }
296
398
  def ssl_bind(host, port, opts)
297
399
  verify = opts.fetch(:verify_mode, 'none')
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)
298
403
 
299
404
  if defined?(JRUBY_VERSION)
300
405
  keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
301
- 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}"
302
407
  else
303
- 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}"
304
410
  end
305
411
  end
306
412
 
307
413
  # Use +path+ as the file to store the server info state. This is
308
- # used by pumactl to query and control the server.
414
+ # used by +pumactl+ to query and control the server.
309
415
  #
416
+ # @example
417
+ # state_path '/u/apps/lolcat/tmp/pids/puma.state'
310
418
  def state_path(path)
311
419
  @options[:state] = path.to_s
312
420
  end
313
421
 
314
- # *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.
315
424
  #
425
+ # The default is 0.
426
+ #
427
+ # @note Cluster mode only.
316
428
  def workers(count)
317
429
  @options[:workers] = count.to_i
318
430
  end
319
431
 
320
- # *Cluster mode only* Code to run immediately before master process
432
+ # Code to run immediately before master process
321
433
  # forks workers (once on boot). These hooks can block if necessary
322
- # to wait for background operations unknown to puma to finish before
434
+ # to wait for background operations unknown to Puma to finish before
323
435
  # the process terminates.
324
- # This can be used to close any connections to remote servers (database, redis, ...)
325
- # 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.
326
438
  #
327
- # This can be called multiple times to add hooks.
439
+ # This can be called multiple times to add several hooks.
328
440
  #
441
+ # @note Cluster mode only.
442
+ # @example
443
+ # before_fork do
444
+ # puts "Starting workers..."
445
+ # end
329
446
  def before_fork(&block)
330
447
  @options[:before_fork] ||= []
331
448
  @options[:before_fork] << block
332
449
  end
333
450
 
334
- # *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
335
452
  # the process before booting the app.
336
453
  #
337
- # This can be called multiple times to add hooks.
454
+ # This can be called multiple times to add several hooks.
338
455
  #
456
+ # @note Cluster mode only.
457
+ # @example
458
+ # on_worker_fork do
459
+ # puts 'Before worker fork...'
460
+ # end
339
461
  def on_worker_boot(&block)
340
462
  @options[:before_worker_boot] ||= []
341
463
  @options[:before_worker_boot] << block
342
464
  end
343
465
 
344
- # *Cluster mode only* Code to run immediately before a worker shuts
466
+ # Code to run immediately before a worker shuts
345
467
  # down (after it has finished processing HTTP requests). These hooks
346
468
  # can block if necessary to wait for background operations unknown
347
- # to puma to finish before the process terminates.
469
+ # to Puma to finish before the process terminates.
348
470
  #
349
- # This can be called multiple times to add hooks.
471
+ # This can be called multiple times to add several hooks.
350
472
  #
473
+ # @note Cluster mode only.
474
+ # @example
475
+ # on_worker_shutdown do
476
+ # puts 'On worker shutdown...'
477
+ # end
351
478
  def on_worker_shutdown(&block)
352
479
  @options[:before_worker_shutdown] ||= []
353
480
  @options[:before_worker_shutdown] << block
354
481
  end
355
482
 
356
- # *Cluster mode only* Code to run in the master when it is
357
- # 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.
358
485
  #
359
- # This can be called multiple times to add hooks.
486
+ # This can be called multiple times to add several hooks.
360
487
  #
488
+ # @note Cluster mode only.
489
+ # @example
490
+ # on_worker_fork do
491
+ # puts 'Before worker fork...'
492
+ # end
361
493
  def on_worker_fork(&block)
362
494
  @options[:before_worker_fork] ||= []
363
495
  @options[:before_worker_fork] << block
364
496
  end
365
497
 
366
- # *Cluster mode only* Code to run in the master after it starts
367
- # 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.
368
500
  #
369
- # This can be called multiple times to add hooks.
501
+ # This is called everytime a worker is to be started.
370
502
  #
503
+ # @note Cluster mode only.
504
+ # @example
505
+ # after_worker_fork do
506
+ # puts 'After worker fork...'
507
+ # end
371
508
  def after_worker_fork(&block)
372
509
  @options[:after_worker_fork] ||= []
373
510
  @options[:after_worker_fork] = block
@@ -375,7 +512,26 @@ module Puma
375
512
 
376
513
  alias_method :after_worker_boot, :after_worker_fork
377
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
+
378
529
  # The directory to operate out of.
530
+ #
531
+ # The default is the current directory.
532
+ #
533
+ # @example
534
+ # directory '/u/apps/lolcat'
379
535
  def directory(dir)
380
536
  @options[:directory] = dir.to_s
381
537
  end
@@ -386,22 +542,28 @@ module Puma
386
542
  directory dir
387
543
  end
388
544
 
389
- # 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.
390
546
  def tcp_mode
391
547
  @options[:mode] = :tcp
392
548
  end
393
549
 
394
- # *Cluster mode only* Preload the application before starting
395
- # the workers and setting up the listen ports. This conflicts
396
- # 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.
397
552
  #
553
+ # @note Cluster mode only.
554
+ # @example
555
+ # preload_app!
398
556
  def preload_app!(answer=true)
399
557
  @options[:preload_app] = answer
400
558
  end
401
559
 
402
- # Use +obj+ or +block+ as the low level error handler. This allows a config file to
403
- # 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.
404
562
  #
563
+ # @example
564
+ # lowlevel_error_handler do |err|
565
+ # [200, {}, ["error page"]]
566
+ # end
405
567
  def lowlevel_error_handler(obj=nil, &block)
406
568
  obj ||= block
407
569
  raise "Provide either a #call'able or a block" unless obj
@@ -411,38 +573,82 @@ module Puma
411
573
  # This option is used to allow your app and its gems to be
412
574
  # properly reloaded when not using preload.
413
575
  #
414
- # 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
415
577
  # context of Bundler, it will cleanup the environment and
416
578
  # re-run itself outside the Bundler environment, but directly
417
579
  # using the files that Bundler has setup.
418
580
  #
419
- # This means that puma is now decoupled from your Bundler
581
+ # This means that Puma is now decoupled from your Bundler
420
582
  # context and when each worker loads, it will be loading a
421
583
  # new Bundler context and thus can float around as the release
422
584
  # dictates.
585
+ #
586
+ # @note This is incompatible with +preload_app!+.
423
587
  def prune_bundler(answer=true)
424
588
  @options[:prune_bundler] = answer
425
589
  end
426
590
 
427
- # Additional text to display in process listing
591
+ # By default, Puma will raise SignalException when SIGTERM is received. In
592
+ # environments where SIGTERM is something expected, you can suppress these
593
+ # with this option.
594
+ #
595
+ # This can be useful for example in Kubernetes, where rolling restart is
596
+ # guaranteed usually on infrastructure level.
597
+ #
598
+ # @example
599
+ # raise_exception_on_sigterm false
600
+ def raise_exception_on_sigterm(answer=true)
601
+ @options[:raise_exception_on_sigterm] = answer
602
+ end
603
+
604
+ # Additional text to display in process listing.
605
+ #
606
+ # If you do not specify a tag, Puma will infer it. If you do not want Puma
607
+ # to add a tag, use an empty string.
608
+ #
609
+ # @example
610
+ # tag 'app name'
611
+ # @example
612
+ # tag ''
428
613
  def tag(string)
429
614
  @options[:tag] = string.to_s
430
615
  end
431
616
 
432
- # *Cluster mode only* Set the timeout for workers in seconds
433
- # When set the master process will terminate any workers
434
- # that have not checked in within the given +timeout+.
435
- # This mitigates hung processes. Default value is 60 seconds.
617
+ # Verifies that all workers have checked in to the master process within
618
+ # the given timeout. If not the worker process will be restarted. This is
619
+ # not a request timeout, it is to protect against a hung or dead process.
620
+ # Setting this value will not protect against slow requests.
621
+ #
622
+ # The minimum value is 6 seconds, the default value is 60 seconds.
623
+ #
624
+ # @note Cluster mode only.
625
+ # @example
626
+ # worker_timeout 60
436
627
  def worker_timeout(timeout)
437
- @options[:worker_timeout] = Integer(timeout)
628
+ timeout = Integer(timeout)
629
+ min = Const::WORKER_CHECK_INTERVAL
630
+
631
+ if timeout <= min
632
+ raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
633
+ end
634
+
635
+ @options[:worker_timeout] = timeout
438
636
  end
439
637
 
440
- # *Cluster mode only* Set the timeout for workers to boot
638
+ # Change the default worker timeout for booting.
639
+ #
640
+ # If unspecified, this defaults to the value of worker_timeout.
641
+ #
642
+ # @note Cluster mode only.
643
+ # @example:
644
+ # worker_boot_timeout 60
441
645
  def worker_boot_timeout(timeout)
442
646
  @options[:worker_boot_timeout] = Integer(timeout)
443
647
  end
444
648
 
445
- # *Cluster mode only* Set the timeout for worker shutdown
649
+ # Set the timeout for worker shutdown
650
+ #
651
+ # @note Cluster mode only.
446
652
  def worker_shutdown_timeout(timeout)
447
653
  @options[:worker_shutdown_timeout] = Integer(timeout)
448
654
  end
@@ -459,7 +665,7 @@ module Puma
459
665
  # Note that setting this to false disables HTTP keepalive and
460
666
  # slow clients will occupy a handler thread while the request
461
667
  # is being sent. A reverse proxy, such as nginx, can handle
462
- # slow clients and queue requests before they reach puma.
668
+ # slow clients and queue requests before they reach Puma.
463
669
  def queue_requests(answer=true)
464
670
  @options[:queue_requests] = answer
465
671
  end
@@ -488,7 +694,7 @@ module Puma
488
694
  # is used, allowing headers such as X-Forwarded-For
489
695
  # to be used as well.
490
696
  # * Any string - this allows you to hardcode remote address to any value
491
- # you wish. Because puma never uses this field anyway, it's
697
+ # you wish. Because Puma never uses this field anyway, it's
492
698
  # format is entirely in your hands.
493
699
  def set_remote_address(val=:socket)
494
700
  case val