puma 4.3.1 → 5.0.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.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +94 -3
  3. data/LICENSE +23 -20
  4. data/README.md +26 -13
  5. data/docs/architecture.md +3 -3
  6. data/docs/deployment.md +9 -3
  7. data/docs/fork_worker.md +31 -0
  8. data/docs/jungle/README.md +13 -0
  9. data/{tools → docs}/jungle/rc.d/README.md +0 -0
  10. data/{tools → docs}/jungle/rc.d/puma +0 -0
  11. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  12. data/{tools → docs}/jungle/upstart/README.md +0 -0
  13. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  14. data/{tools → docs}/jungle/upstart/puma.conf +0 -0
  15. data/docs/signals.md +7 -6
  16. data/docs/systemd.md +1 -63
  17. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  18. data/ext/puma_http11/extconf.rb +4 -3
  19. data/ext/puma_http11/http11_parser.c +3 -1
  20. data/ext/puma_http11/http11_parser.rl +3 -1
  21. data/ext/puma_http11/mini_ssl.c +15 -2
  22. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  23. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  24. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
  25. data/ext/puma_http11/puma_http11.c +7 -38
  26. data/lib/puma.rb +17 -0
  27. data/lib/puma/app/status.rb +18 -3
  28. data/lib/puma/binder.rb +88 -68
  29. data/lib/puma/cli.rb +7 -15
  30. data/lib/puma/client.rb +67 -14
  31. data/lib/puma/cluster.rb +191 -74
  32. data/lib/puma/commonlogger.rb +2 -2
  33. data/lib/puma/configuration.rb +31 -42
  34. data/lib/puma/const.rb +4 -3
  35. data/lib/puma/control_cli.rb +29 -17
  36. data/lib/puma/detect.rb +17 -0
  37. data/lib/puma/dsl.rb +144 -70
  38. data/lib/puma/error_logger.rb +97 -0
  39. data/lib/puma/events.rb +35 -31
  40. data/lib/puma/io_buffer.rb +9 -2
  41. data/lib/puma/jruby_restart.rb +0 -58
  42. data/lib/puma/launcher.rb +49 -31
  43. data/lib/puma/minissl.rb +60 -18
  44. data/lib/puma/minissl/context_builder.rb +0 -3
  45. data/lib/puma/null_io.rb +1 -1
  46. data/lib/puma/plugin.rb +1 -10
  47. data/lib/puma/rack/builder.rb +0 -4
  48. data/lib/puma/reactor.rb +9 -4
  49. data/lib/puma/runner.rb +8 -36
  50. data/lib/puma/server.rb +149 -186
  51. data/lib/puma/single.rb +7 -64
  52. data/lib/puma/state_file.rb +6 -3
  53. data/lib/puma/thread_pool.rb +94 -49
  54. data/lib/rack/handler/puma.rb +1 -3
  55. data/tools/{docker/Dockerfile → Dockerfile} +0 -0
  56. metadata +21 -23
  57. data/docs/tcp_mode.md +0 -96
  58. data/ext/puma_http11/io_buffer.c +0 -155
  59. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  60. data/lib/puma/tcp_logger.rb +0 -41
  61. data/tools/jungle/README.md +0 -19
  62. data/tools/jungle/init.d/README.md +0 -61
  63. data/tools/jungle/init.d/puma +0 -421
  64. data/tools/jungle/init.d/run-puma +0 -18
@@ -3,7 +3,7 @@
3
3
  module Puma
4
4
  # Rack::CommonLogger forwards every request to the given +app+, and
5
5
  # logs a line in the
6
- # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
6
+ # {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
7
7
  # to the +logger+.
8
8
  #
9
9
  # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
@@ -16,7 +16,7 @@ module Puma
16
16
  # (which is called without arguments in order to make the error appear for
17
17
  # sure)
18
18
  class CommonLogger
19
- # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
19
+ # Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
20
20
  #
21
21
  # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
22
  #
@@ -54,9 +54,7 @@ module Puma
54
54
  attr_reader :user_options, :file_options, :default_options
55
55
 
56
56
  def [](key)
57
- return user_options[key] if user_options.key?(key)
58
- return file_options[key] if file_options.key?(key)
59
- return default_options[key] if default_options.key?(key)
57
+ fetch(key)
60
58
  end
61
59
 
62
60
  def []=(key, value)
@@ -64,7 +62,11 @@ module Puma
64
62
  end
65
63
 
66
64
  def fetch(key, default_value = nil)
67
- self[key] || default_value
65
+ return user_options[key] if user_options.key?(key)
66
+ return file_options[key] if file_options.key?(key)
67
+ return default_options[key] if default_options.key?(key)
68
+
69
+ default_value
68
70
  end
69
71
 
70
72
  def all_of(key)
@@ -106,7 +108,7 @@ module Puma
106
108
  #
107
109
  # It also handles loading plugins.
108
110
  #
109
- # > Note: `:port` and `:host` are not valid keys. By they time they make it to the
111
+ # > Note: `:port` and `:host` are not valid keys. By the time they make it to the
110
112
  # configuration options they are expected to be incorporated into a `:binds` key.
111
113
  # Under the hood the DSL maps `port` and `host` calls to `:binds`
112
114
  #
@@ -137,6 +139,10 @@ module Puma
137
139
  @file_dsl = DSL.new(@options.file_options, self)
138
140
  @default_dsl = DSL.new(@options.default_options, self)
139
141
 
142
+ if !@options[:prune_bundler]
143
+ default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
144
+ end
145
+
140
146
  if block
141
147
  configure(&block)
142
148
  end
@@ -167,22 +173,26 @@ module Puma
167
173
  self
168
174
  end
169
175
 
176
+ # @version 5.0.0
177
+ def default_max_threads
178
+ Puma.mri? ? 5 : 16
179
+ end
180
+
170
181
  def puma_default_options
171
182
  {
172
- :min_threads => 0,
173
- :max_threads => 16,
183
+ :min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
184
+ :max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
174
185
  :log_requests => false,
175
186
  :debug => false,
176
187
  :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
177
- :workers => 0,
178
- :daemon => false,
188
+ :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
179
189
  :mode => :http,
180
190
  :worker_timeout => DefaultWorkerTimeout,
181
191
  :worker_boot_timeout => DefaultWorkerTimeout,
182
192
  :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
183
193
  :remote_address => :socket,
184
194
  :tag => method(:infer_tag),
185
- :environment => -> { ENV['RACK_ENV'] || "development" },
195
+ :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
186
196
  :rackup => DefaultRackup,
187
197
  :logger => STDOUT,
188
198
  :persistent_timeout => Const::PERSISTENT_TIMEOUT,
@@ -245,14 +255,6 @@ module Puma
245
255
  def app
246
256
  found = options[:app] || load_rackup
247
257
 
248
- if @options[:mode] == :tcp
249
- require 'puma/tcp_logger'
250
-
251
- logger = @options[:logger]
252
- quiet = !@options[:log_requests]
253
- return TCPLogger.new(logger, found, quiet)
254
- end
255
-
256
258
  if @options[:log_requests]
257
259
  require 'puma/commonlogger'
258
260
  logger = @options[:logger]
@@ -275,8 +277,15 @@ module Puma
275
277
  @plugins.create name
276
278
  end
277
279
 
278
- def run_hooks(key, arg)
279
- @options.all_of(key).each { |b| b.call arg }
280
+ def run_hooks(key, arg, events)
281
+ @options.all_of(key).each do |b|
282
+ begin
283
+ b.call arg
284
+ rescue => e
285
+ events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
286
+ events.debug e.backtrace.join("\n")
287
+ end
288
+ end
280
289
  end
281
290
 
282
291
  def self.temp_path
@@ -332,29 +341,9 @@ module Puma
332
341
  end
333
342
 
334
343
  def self.random_token
335
- begin
336
- require 'openssl'
337
- rescue LoadError
338
- end
339
-
340
- count = 16
341
-
342
- bytes = nil
343
-
344
- if defined? OpenSSL::Random
345
- bytes = OpenSSL::Random.random_bytes(count)
346
- elsif File.exist?("/dev/urandom")
347
- File.open('/dev/urandom') { |f| bytes = f.read(count) }
348
- end
349
-
350
- if bytes
351
- token = "".dup
352
- bytes.each_byte { |b| token << b.to_s(16) }
353
- else
354
- token = (0..count).to_a.map { rand(255).to_s(16) }.join
355
- end
344
+ require 'securerandom' unless defined?(SecureRandom)
356
345
 
357
- return token
346
+ SecureRandom.hex(16)
358
347
  end
359
348
  end
360
349
  end
@@ -100,8 +100,9 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "4.3.1".freeze
104
- CODE_NAME = "Mysterious Traveller".freeze
103
+ PUMA_VERSION = VERSION = "5.0.0".freeze
104
+ CODE_NAME = "Spoony Bard".freeze
105
+
105
106
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
107
 
107
108
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -175,7 +176,6 @@ module Puma
175
176
  PORT_443 = "443".freeze
176
177
  LOCALHOST = "localhost".freeze
177
178
  LOCALHOST_IP = "127.0.0.1".freeze
178
- LOCALHOST_ADDR = "127.0.0.1:0".freeze
179
179
 
180
180
  SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
181
181
  HTTP_11 = "HTTP/1.1".freeze
@@ -228,6 +228,7 @@ module Puma
228
228
  COLON = ": ".freeze
229
229
 
230
230
  NEWLINE = "\n".freeze
231
+ HTTP_INJECTION_REGEX = /[\r\n]/.freeze
231
232
 
232
233
  HIJACK_P = "rack.hijack?".freeze
233
234
  HIJACK = "rack.hijack".freeze
@@ -11,7 +11,10 @@ require 'socket'
11
11
  module Puma
12
12
  class ControlCLI
13
13
 
14
- COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
14
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats thread-backtraces refork}
15
+
16
+ # @version 5.0.0
17
+ PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}
15
18
 
16
19
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
17
20
  @state = nil
@@ -22,7 +25,7 @@ module Puma
22
25
  @control_auth_token = nil
23
26
  @config_file = nil
24
27
  @command = nil
25
- @environment = ENV['RACK_ENV']
28
+ @environment = ENV['RACK_ENV'] || ENV['RAILS_ENV']
26
29
 
27
30
  @argv = argv.dup
28
31
  @stdout = stdout
@@ -81,6 +84,15 @@ module Puma
81
84
 
82
85
  @command = argv.shift
83
86
 
87
+ # check presence of command
88
+ unless @command
89
+ raise "Available commands: #{COMMANDS.join(", ")}"
90
+ end
91
+
92
+ unless COMMANDS.include? @command
93
+ raise "Invalid command: #{@command}"
94
+ end
95
+
84
96
  unless @config_file == '-'
85
97
  environment = @environment || 'development'
86
98
 
@@ -99,16 +111,6 @@ module Puma
99
111
  @pidfile ||= config.options[:pidfile]
100
112
  end
101
113
  end
102
-
103
- # check present of command
104
- unless @command
105
- raise "Available commands: #{COMMANDS.join(", ")}"
106
- end
107
-
108
- unless COMMANDS.include? @command
109
- raise "Invalid command: #{@command}"
110
- end
111
-
112
114
  rescue => e
113
115
  @stdout.puts e.message
114
116
  exit 1
@@ -145,8 +147,9 @@ module Puma
145
147
  require 'openssl'
146
148
  OpenSSL::SSL::SSLSocket.new(
147
149
  TCPSocket.new(uri.host, uri.port),
148
- OpenSSL::SSL::SSLContext.new
149
- ).tap(&:connect)
150
+ OpenSSL::SSL::SSLContext.new)
151
+ .tap { |ssl| ssl.sync_close = true } # default is false
152
+ .tap(&:connect)
150
153
  when "tcp"
151
154
  TCPSocket.new uri.host, uri.port
152
155
  when "unix"
@@ -187,10 +190,16 @@ module Puma
187
190
  end
188
191
 
189
192
  message "Command #{@command} sent success"
190
- message response.last if @command == "stats" || @command == "gc-stats"
193
+ message response.last if PRINTABLE_COMMANDS.include?(@command)
191
194
  end
192
195
  ensure
193
- server.close if server && !server.closed?
196
+ if server
197
+ if uri.scheme == "ssl"
198
+ server.sysclose
199
+ else
200
+ server.close unless server.closed?
201
+ end
202
+ end
194
203
  end
195
204
 
196
205
  def send_signal
@@ -231,6 +240,9 @@ module Puma
231
240
 
232
241
  return
233
242
 
243
+ when "refork"
244
+ Process.kill "SIGURG", @pid
245
+
234
246
  else
235
247
  return
236
248
  end
@@ -262,7 +274,7 @@ module Puma
262
274
  exit 1
263
275
  end
264
276
 
265
- private
277
+ private
266
278
  def start
267
279
  require 'puma/cli'
268
280
 
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Puma
4
+ # at present, MiniSSL::Engine is only defined in extension code, not in minissl.rb
5
+ HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
6
+
7
+ def self.ssl?
8
+ HAS_SSL
9
+ end
10
+
4
11
  IS_JRUBY = defined?(JRUBY_VERSION)
5
12
 
6
13
  def self.jruby?
@@ -12,4 +19,14 @@ module Puma
12
19
  def self.windows?
13
20
  IS_WINDOWS
14
21
  end
22
+
23
+ # @version 5.0.0
24
+ def self.mri?
25
+ RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?
26
+ end
27
+
28
+ # @version 5.0.0
29
+ def self.forkable?
30
+ ::Process.respond_to?(:fork)
31
+ end
15
32
  end
@@ -14,22 +14,23 @@ module Puma
14
14
  # end
15
15
  # config.load
16
16
  #
17
- # puts config.options[:binds]
18
- # "tcp://127.0.0.1:3001"
17
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3001"
19
18
  #
20
19
  # Used to load file:
21
20
  #
22
21
  # $ cat puma_config.rb
23
- # port 3002
22
+ # port 3002
23
+ #
24
+ # Resulting configuration:
24
25
  #
25
26
  # config = Configuration.new(config_file: "puma_config.rb")
26
27
  # config.load
27
28
  #
28
- # puts config.options[:binds]
29
- # # => "tcp://127.0.0.1:3002"
29
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3002"
30
30
  #
31
31
  # You can also find many examples being used by the test suite in
32
32
  # +test/config+.
33
+ #
33
34
  class DSL
34
35
  include ConfigDefault
35
36
 
@@ -98,6 +99,9 @@ module Puma
98
99
  # [body]
99
100
  # ]
100
101
  # end
102
+ #
103
+ # @see Puma::Configuration#app
104
+ #
101
105
  def app(obj=nil, &block)
102
106
  obj ||= block
103
107
 
@@ -160,12 +164,12 @@ module Puma
160
164
  #
161
165
  # You can use query parameters within the url to specify options:
162
166
  #
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+.
167
+ # * Set the socket backlog depth with +backlog+, default is 1024.
168
+ # * Set up an SSL certificate with +key+ & +cert+.
169
+ # * Set whether to optimize for low latency instead of throughput with
170
+ # +low_latency+, default is to optimize for low latency. This is done
171
+ # via +Socket::TCP_NODELAY+.
172
+ # * Set socket permissions with +umask+.
169
173
  #
170
174
  # @example Backlog depth
171
175
  # bind 'unix:///var/run/puma.sock?backlog=512'
@@ -175,6 +179,9 @@ module Puma
175
179
  # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
180
  # @example Socket permissions
177
181
  # bind 'unix:///var/run/puma.sock?umask=0111'
182
+ # @see Puma::Runner#load_and_bind
183
+ # @see Puma::Cluster#run
184
+ #
178
185
  def bind(url)
179
186
  @options[:binds] ||= []
180
187
  @options[:binds] << url
@@ -193,13 +200,14 @@ module Puma
193
200
  bind "tcp://#{host}:#{port}"
194
201
  end
195
202
 
196
- # Define how long persistent connections can be idle before Puma closes
197
- # them.
203
+ # Define how long persistent connections can be idle before Puma closes them.
204
+ # @see Puma::Server.new
198
205
  def persistent_timeout(seconds)
199
206
  @options[:persistent_timeout] = Integer(seconds)
200
207
  end
201
208
 
202
209
  # Define how long the tcp socket stays open, if no data has been received.
210
+ # @see Puma::Server.new
203
211
  def first_data_timeout(seconds)
204
212
  @options[:first_data_timeout] = Integer(seconds)
205
213
  end
@@ -210,24 +218,11 @@ module Puma
210
218
  @options[:clean_thread_locals] = which
211
219
  end
212
220
 
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
221
+ # When shutting down, drain the accept socket of pending connections and
222
+ # process them. This loops over the accept socket until there are no more
223
+ # read events and then stops looking and waits for the requests to finish.
224
+ # @see Puma::Server#graceful_shutdown
220
225
  #
221
- # @example
222
- # daemonize false
223
- def daemonize(which=true)
224
- @options[:daemon] = which
225
- end
226
-
227
- # When shutting down, drain the accept socket of pending
228
- # connections and process them. This loops over the accept
229
- # socket until there are no more read events and then stops
230
- # looking and waits for the requests to finish.
231
226
  def drain_on_shutdown(which=true)
232
227
  @options[:drain_on_shutdown] = which
233
228
  end
@@ -250,6 +245,7 @@ module Puma
250
245
  #
251
246
  # Puma always waits a few seconds after killing a thread for it to try
252
247
  # to finish up it's work, even in :immediately mode.
248
+ # @see Puma::Server#graceful_shutdown
253
249
  def force_shutdown_after(val=:forever)
254
250
  i = case val
255
251
  when :forever
@@ -257,7 +253,7 @@ module Puma
257
253
  when :immediately
258
254
  0
259
255
  else
260
- Integer(val)
256
+ Float(val)
261
257
  end
262
258
 
263
259
  @options[:force_shutdown_after] = i
@@ -322,20 +318,14 @@ module Puma
322
318
  # @example
323
319
  # rackup '/u/apps/lolcat/config.ru'
324
320
  def rackup(path)
325
- @options[:rackup] = path.to_s
326
- end
327
-
328
- # Run Puma in TCP mode
329
- #
330
- def tcp_mode!
331
- @options[:mode] = :tcp
321
+ @options[:rackup] ||= path.to_s
332
322
  end
333
323
 
334
324
  def early_hints(answer=true)
335
325
  @options[:early_hints] = answer
336
326
  end
337
327
 
338
- # Redirect STDOUT and STDERR to files specified. The +append+ parameter
328
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
339
329
  # specifies whether the output is appended, the default is +false+.
340
330
  #
341
331
  # @example
@@ -376,8 +366,8 @@ module Puma
376
366
  @options[:max_threads] = max
377
367
  end
378
368
 
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.
369
+ # Instead of `bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'` you
370
+ # can also use the this method.
381
371
  #
382
372
  # @example
383
373
  # ssl_bind '127.0.0.1', '9292', {
@@ -419,12 +409,23 @@ module Puma
419
409
  @options[:state] = path.to_s
420
410
  end
421
411
 
412
+ # Use +permission+ to restrict permissions for the state file.
413
+ #
414
+ # @example
415
+ # state_permission 0600
416
+ # @version 5.0.0
417
+ #
418
+ def state_permission(permission)
419
+ @options[:state_permission] = permission
420
+ end
421
+
422
422
  # How many worker processes to run. Typically this is set to
423
- # to the number of available cores.
423
+ # the number of available cores.
424
424
  #
425
425
  # The default is 0.
426
426
  #
427
427
  # @note Cluster mode only.
428
+ # @see Puma::Cluster
428
429
  def workers(count)
429
430
  @options[:workers] = count.to_i
430
431
  end
@@ -455,8 +456,8 @@ module Puma
455
456
  #
456
457
  # @note Cluster mode only.
457
458
  # @example
458
- # on_worker_fork do
459
- # puts 'Before worker fork...'
459
+ # on_worker_boot do
460
+ # puts 'Before worker boot...'
460
461
  # end
461
462
  def on_worker_boot(&block)
462
463
  @options[:before_worker_boot] ||= []
@@ -512,6 +513,29 @@ module Puma
512
513
 
513
514
  alias_method :after_worker_boot, :after_worker_fork
514
515
 
516
+ # When `fork_worker` is enabled, code to run in Worker 0
517
+ # before all other workers are re-forked from this process,
518
+ # after the server has temporarily stopped serving requests
519
+ # (once per complete refork cycle).
520
+ #
521
+ # This can be used to trigger extra garbage-collection to maximize
522
+ # copy-on-write efficiency, or close any connections to remote servers
523
+ # (database, Redis, ...) that were opened while the server was running.
524
+ #
525
+ # This can be called multiple times to add several hooks.
526
+ #
527
+ # @note Cluster mode with `fork_worker` enabled only.
528
+ # @example
529
+ # on_refork do
530
+ # 3.times {GC.start}
531
+ # end
532
+ # @version 5.0.0
533
+ #
534
+ def on_refork(&block)
535
+ @options[:before_refork] ||= []
536
+ @options[:before_refork] << block
537
+ end
538
+
515
539
  # Code to run out-of-band when the worker is idle.
516
540
  # These hooks run immediately after a request has finished
517
541
  # processing and there are no busy threads on the worker.
@@ -536,17 +560,6 @@ module Puma
536
560
  @options[:directory] = dir.to_s
537
561
  end
538
562
 
539
- # DEPRECATED: The directory to operate out of.
540
- def worker_directory(dir)
541
- $stderr.puts "worker_directory is deprecated. Please use `directory`"
542
- directory dir
543
- end
544
-
545
- # Run the app as a raw TCP app instead of an HTTP rack app.
546
- def tcp_mode
547
- @options[:mode] = :tcp
548
- end
549
-
550
563
  # Preload the application before starting the workers; this conflicts with
551
564
  # phased restart feature. This is off by default.
552
565
  #
@@ -583,7 +596,7 @@ module Puma
583
596
  # new Bundler context and thus can float around as the release
584
597
  # dictates.
585
598
  #
586
- # See also: extra_runtime_dependencies
599
+ # @see extra_runtime_dependencies
587
600
  #
588
601
  # @note This is incompatible with +preload_app!+.
589
602
  # @note This is only supported for RubyGems 2.2+
@@ -600,6 +613,9 @@ module Puma
600
613
  #
601
614
  # @example
602
615
  # raise_exception_on_sigterm false
616
+ # @see Puma::Launcher#setup_signals
617
+ # @see Puma::Cluster#setup_signals
618
+ #
603
619
  def raise_exception_on_sigterm(answer=true)
604
620
  @options[:raise_exception_on_sigterm] = answer
605
621
  end
@@ -615,6 +631,8 @@ module Puma
615
631
  # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
616
632
  # @example
617
633
  # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
634
+ # @see Puma::Launcher#extra_runtime_deps_directories
635
+ #
618
636
  def extra_runtime_dependencies(answer = [])
619
637
  @options[:extra_runtime_dependencies] = Array(answer)
620
638
  end
@@ -642,6 +660,8 @@ module Puma
642
660
  # @note Cluster mode only.
643
661
  # @example
644
662
  # worker_timeout 60
663
+ # @see Puma::Cluster::Worker#ping_timeout
664
+ #
645
665
  def worker_timeout(timeout)
646
666
  timeout = Integer(timeout)
647
667
  min = Const::WORKER_CHECK_INTERVAL
@@ -658,15 +678,20 @@ module Puma
658
678
  # If unspecified, this defaults to the value of worker_timeout.
659
679
  #
660
680
  # @note Cluster mode only.
661
- # @example:
681
+ #
682
+ # @example
662
683
  # worker_boot_timeout 60
684
+ # @see Puma::Cluster::Worker#ping_timeout
685
+ #
663
686
  def worker_boot_timeout(timeout)
664
687
  @options[:worker_boot_timeout] = Integer(timeout)
665
688
  end
666
689
 
667
- # Set the timeout for worker shutdown
690
+ # Set the timeout for worker shutdown.
668
691
  #
669
692
  # @note Cluster mode only.
693
+ # @see Puma::Cluster::Worker#term
694
+ #
670
695
  def worker_shutdown_timeout(timeout)
671
696
  @options[:worker_shutdown_timeout] = Integer(timeout)
672
697
  end
@@ -684,6 +709,7 @@ module Puma
684
709
  # slow clients will occupy a handler thread while the request
685
710
  # is being sent. A reverse proxy, such as nginx, can handle
686
711
  # slow clients and queue requests before they reach Puma.
712
+ # @see Puma::Server
687
713
  def queue_requests(answer=true)
688
714
  @options[:queue_requests] = answer
689
715
  end
@@ -691,10 +717,25 @@ module Puma
691
717
  # When a shutdown is requested, the backtraces of all the
692
718
  # threads will be written to $stdout. This can help figure
693
719
  # out why shutdown is hanging.
720
+ #
694
721
  def shutdown_debug(val=true)
695
722
  @options[:shutdown_debug] = val
696
723
  end
697
724
 
725
+
726
+ # Attempts to route traffic to less-busy workers by causing them to delay
727
+ # listening on the socket, allowing workers which are not processing any
728
+ # requests to pick up new requests first.
729
+ #
730
+ # Only works on MRI. For all other interpreters, this setting does nothing.
731
+ # @see Puma::Server#handle_servers
732
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
733
+ # @version 5.0.0
734
+ #
735
+ def wait_for_less_busy_worker(val=0.005)
736
+ @options[:wait_for_less_busy_worker] = val.to_f
737
+ end
738
+
698
739
  # Control how the remote address of the connection is set. This
699
740
  # is configurable because to calculate the true socket peer address
700
741
  # a kernel syscall is required which for very fast rack handlers
@@ -702,18 +743,18 @@ module Puma
702
743
  #
703
744
  # There are 4 possible values:
704
745
  #
705
- # * :socket (the default) - read the peername from the socket using the
706
- # syscall. This is the normal behavior.
707
- # * :localhost - set the remote address to "127.0.0.1"
708
- # * header: http_header - set the remote address to the value of the
709
- # provided http header. For instance:
710
- # `set_remote_address header: "X-Real-IP"`.
711
- # Only the first word (as separated by spaces or comma)
712
- # is used, allowing headers such as X-Forwarded-For
713
- # to be used as well.
714
- # * Any string - this allows you to hardcode remote address to any value
715
- # you wish. Because Puma never uses this field anyway, it's
716
- # format is entirely in your hands.
746
+ # 1. **:socket** (the default) - read the peername from the socket using the
747
+ # syscall. This is the normal behavior.
748
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
749
+ # 3. **header: <http_header>**- set the remote address to the value of the
750
+ # provided http header. For instance:
751
+ # `set_remote_address header: "X-Real-IP"`.
752
+ # Only the first word (as separated by spaces or comma) is used, allowing
753
+ # headers such as X-Forwarded-For to be used as well.
754
+ # 4. **\<Any string\>** - this allows you to hardcode remote address to any value
755
+ # you wish. Because Puma never uses this field anyway, it's format is
756
+ # entirely in your hands.
757
+ #
717
758
  def set_remote_address(val=:socket)
718
759
  case val
719
760
  when :socket
@@ -736,5 +777,38 @@ module Puma
736
777
  end
737
778
  end
738
779
 
780
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
781
+ # This option is similar to `preload_app` because the app is preloaded before forking,
782
+ # but it is compatible with phased restart.
783
+ #
784
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
785
+ # in a running app.
786
+ #
787
+ # A refork will automatically trigger once after the specified number of requests
788
+ # (default 1000), or pass 0 to disable auto refork.
789
+ #
790
+ # @note Cluster mode only.
791
+ # @version 5.0.0
792
+ #
793
+ def fork_worker(after_requests=1000)
794
+ @options[:fork_worker] = Integer(after_requests)
795
+ end
796
+
797
+ # When enabled, Puma will GC 4 times before forking workers.
798
+ # If available (Ruby 2.7+), we will also call GC.compact.
799
+ # Not recommended for non-MRI Rubies.
800
+ #
801
+ # Based on the work of Koichi Sasada and Aaron Patterson, this option may
802
+ # decrease memory utilization of preload-enabled cluster-mode Pumas. It will
803
+ # also increase time to boot and fork. See your logs for details on how much
804
+ # time this adds to your boot process. For most apps, it will be less than one
805
+ # second.
806
+ #
807
+ # @see Puma::Cluster#nakayoshi_gc
808
+ # @version 5.0.0
809
+ #
810
+ def nakayoshi_fork(enabled=true)
811
+ @options[:nakayoshi_fork] = enabled
812
+ end
739
813
  end
740
814
  end