puma 4.3.12 → 6.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1591 -521
  3. data/LICENSE +23 -20
  4. data/README.md +130 -42
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +31 -0
  10. data/docs/jungle/README.md +9 -0
  11. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  12. data/{tools → docs}/jungle/rc.d/puma +2 -2
  13. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  14. data/docs/kubernetes.md +66 -0
  15. data/docs/nginx.md +1 -1
  16. data/docs/plugins.md +15 -15
  17. data/docs/rails_dev_mode.md +28 -0
  18. data/docs/restart.md +46 -23
  19. data/docs/signals.md +13 -11
  20. data/docs/stats.md +142 -0
  21. data/docs/systemd.md +85 -128
  22. data/docs/testing_benchmarks_local_files.md +150 -0
  23. data/docs/testing_test_rackup_ci_files.md +36 -0
  24. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  25. data/ext/puma_http11/ext_help.h +1 -1
  26. data/ext/puma_http11/extconf.rb +49 -12
  27. data/ext/puma_http11/http11_parser.c +46 -48
  28. data/ext/puma_http11/http11_parser.h +2 -2
  29. data/ext/puma_http11/http11_parser.java.rl +3 -3
  30. data/ext/puma_http11/http11_parser.rl +3 -3
  31. data/ext/puma_http11/http11_parser_common.rl +2 -2
  32. data/ext/puma_http11/mini_ssl.c +250 -93
  33. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  34. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  35. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
  36. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  37. data/ext/puma_http11/puma_http11.c +46 -57
  38. data/lib/puma/app/status.rb +52 -38
  39. data/lib/puma/binder.rb +232 -119
  40. data/lib/puma/cli.rb +33 -33
  41. data/lib/puma/client.rb +125 -87
  42. data/lib/puma/cluster/worker.rb +175 -0
  43. data/lib/puma/cluster/worker_handle.rb +97 -0
  44. data/lib/puma/cluster.rb +224 -229
  45. data/lib/puma/commonlogger.rb +2 -2
  46. data/lib/puma/configuration.rb +112 -87
  47. data/lib/puma/const.rb +25 -22
  48. data/lib/puma/control_cli.rb +99 -79
  49. data/lib/puma/detect.rb +31 -2
  50. data/lib/puma/dsl.rb +423 -110
  51. data/lib/puma/error_logger.rb +112 -0
  52. data/lib/puma/events.rb +16 -115
  53. data/lib/puma/io_buffer.rb +34 -2
  54. data/lib/puma/jruby_restart.rb +2 -59
  55. data/lib/puma/json_serialization.rb +96 -0
  56. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  57. data/lib/puma/launcher.rb +170 -148
  58. data/lib/puma/log_writer.rb +137 -0
  59. data/lib/puma/minissl/context_builder.rb +35 -19
  60. data/lib/puma/minissl.rb +213 -55
  61. data/lib/puma/null_io.rb +18 -1
  62. data/lib/puma/plugin/tmp_restart.rb +1 -1
  63. data/lib/puma/plugin.rb +3 -12
  64. data/lib/puma/rack/builder.rb +5 -9
  65. data/lib/puma/rack_default.rb +1 -1
  66. data/lib/puma/reactor.rb +85 -369
  67. data/lib/puma/request.rb +607 -0
  68. data/lib/puma/runner.rb +83 -77
  69. data/lib/puma/server.rb +305 -789
  70. data/lib/puma/single.rb +18 -74
  71. data/lib/puma/state_file.rb +45 -8
  72. data/lib/puma/systemd.rb +47 -0
  73. data/lib/puma/thread_pool.rb +137 -66
  74. data/lib/puma/util.rb +21 -4
  75. data/lib/puma.rb +54 -5
  76. data/lib/rack/handler/puma.rb +11 -12
  77. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  78. metadata +31 -23
  79. data/docs/tcp_mode.md +0 -96
  80. data/ext/puma_http11/io_buffer.c +0 -155
  81. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  82. data/lib/puma/accept_nonblock.rb +0 -29
  83. data/lib/puma/tcp_logger.rb +0 -41
  84. data/tools/jungle/README.md +0 -19
  85. data/tools/jungle/init.d/README.md +0 -61
  86. data/tools/jungle/init.d/puma +0 -421
  87. data/tools/jungle/init.d/run-puma +0 -18
  88. data/tools/jungle/upstart/README.md +0 -61
  89. data/tools/jungle/upstart/puma-manager.conf +0 -31
  90. data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/dsl.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/const'
3
+ require_relative 'const'
4
+ require_relative 'util'
4
5
 
5
6
  module Puma
6
7
  # The methods that are available for use inside the configuration file.
@@ -14,24 +15,108 @@ module Puma
14
15
  # end
15
16
  # config.load
16
17
  #
17
- # puts config.options[:binds]
18
- # "tcp://127.0.0.1:3001"
18
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3001"
19
19
  #
20
20
  # Used to load file:
21
21
  #
22
22
  # $ cat puma_config.rb
23
- # port 3002
23
+ # port 3002
24
+ #
25
+ # Resulting configuration:
24
26
  #
25
27
  # config = Configuration.new(config_file: "puma_config.rb")
26
28
  # config.load
27
29
  #
28
- # puts config.options[:binds]
29
- # # => "tcp://127.0.0.1:3002"
30
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3002"
30
31
  #
31
32
  # You can also find many examples being used by the test suite in
32
33
  # +test/config+.
34
+ #
35
+ # Puma v6 adds the option to specify a key name (String or Symbol) to the
36
+ # hooks that run inside the forked workers. All the hooks run inside the
37
+ # {Puma::Cluster::Worker#run} method.
38
+ #
39
+ # Previously, the worker index and the LogWriter instance were passed to the
40
+ # hook blocks/procs. If a key name is specified, a hash is passed as the last
41
+ # parameter. This allows storage of data, typically objects that are created
42
+ # before the worker that need to be passed to the hook when the worker is shutdown.
43
+ #
44
+ # The following hooks have been updated:
45
+ #
46
+ # | DSL Method | Options Key | Fork Block Location |
47
+ # | on_worker_boot | :before_worker_boot | inside, before |
48
+ # | on_worker_shutdown | :before_worker_shutdown | inside, after |
49
+ # | on_refork | :before_refork | inside |
50
+ #
33
51
  class DSL
34
- include ConfigDefault
52
+ ON_WORKER_KEY = [String, Symbol].freeze
53
+
54
+ # convenience method so logic can be used in CI
55
+ # @see ssl_bind
56
+ #
57
+ def self.ssl_bind_str(host, port, opts)
58
+ verify = opts.fetch(:verify_mode, 'none').to_s
59
+
60
+ tls_str =
61
+ if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
62
+ elsif opts[:no_tlsv1] then '&no_tlsv1=true'
63
+ else ''
64
+ end
65
+
66
+ ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
67
+
68
+ backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
69
+
70
+ if defined?(JRUBY_VERSION)
71
+ cipher_suites = opts[:ssl_cipher_list] ? "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil # old name
72
+ cipher_suites = "#{cipher_suites}&cipher_suites=#{opts[:cipher_suites]}" if opts[:cipher_suites]
73
+ protocols = opts[:protocols] ? "&protocols=#{opts[:protocols]}" : nil
74
+
75
+ keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
76
+ keystore_additions = "#{keystore_additions}&keystore-type=#{opts[:keystore_type]}" if opts[:keystore_type]
77
+ if opts[:truststore]
78
+ truststore_additions = "&truststore=#{opts[:truststore]}"
79
+ truststore_additions = "#{truststore_additions}&truststore-pass=#{opts[:truststore_pass]}" if opts[:truststore_pass]
80
+ truststore_additions = "#{truststore_additions}&truststore-type=#{opts[:truststore_type]}" if opts[:truststore_type]
81
+ end
82
+
83
+ "ssl://#{host}:#{port}?#{keystore_additions}#{truststore_additions}#{cipher_suites}#{protocols}" \
84
+ "&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
85
+ else
86
+ ssl_cipher_filter = opts[:ssl_cipher_filter] ? "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
87
+ v_flags = (ary = opts[:verification_flags]) ? "&verification_flags=#{Array(ary).join ','}" : nil
88
+
89
+ cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(cert)}" : nil
90
+ key_flags = (key = opts[:key]) ? "&key=#{Puma::Util.escape(key)}" : nil
91
+
92
+ reuse_flag =
93
+ if (reuse = opts[:reuse])
94
+ if reuse == true
95
+ '&reuse=dflt'
96
+ elsif reuse.is_a?(Hash) && (reuse.key?(:size) || reuse.key?(:timeout))
97
+ val = +''
98
+ if (size = reuse[:size]) && Integer === size
99
+ val << size.to_s
100
+ end
101
+ if (timeout = reuse[:timeout]) && Integer === timeout
102
+ val << ",#{timeout}"
103
+ end
104
+ if val.empty?
105
+ nil
106
+ else
107
+ "&reuse=#{val}"
108
+ end
109
+ else
110
+ nil
111
+ end
112
+ else
113
+ nil
114
+ end
115
+
116
+ "ssl://#{host}:#{port}?#{cert_flags}#{key_flags}#{ssl_cipher_filter}" \
117
+ "#{reuse_flag}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
118
+ end
119
+ end
35
120
 
36
121
  def initialize(options, config)
37
122
  @config = config
@@ -65,7 +150,7 @@ module Puma
65
150
  end
66
151
 
67
152
  def default_host
68
- @options[:default_host] || Configuration::DefaultTCPHost
153
+ @options[:default_host] || Configuration::DEFAULTS[:tcp_host]
69
154
  end
70
155
 
71
156
  def inject(&blk)
@@ -98,6 +183,9 @@ module Puma
98
183
  # [body]
99
184
  # ]
100
185
  # end
186
+ #
187
+ # @see Puma::Configuration#app
188
+ #
101
189
  def app(obj=nil, &block)
102
190
  obj ||= block
103
191
 
@@ -153,19 +241,19 @@ module Puma
153
241
  end
154
242
 
155
243
  # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
156
- # accepted protocols. Multiple urls can be bound to, calling `bind` does
244
+ # accepted protocols. Multiple urls can be bound to, calling +bind+ does
157
245
  # not overwrite previous bindings.
158
246
  #
159
247
  # The default is "tcp://0.0.0.0:9292".
160
248
  #
161
249
  # You can use query parameters within the url to specify options:
162
250
  #
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+.
251
+ # * Set the socket backlog depth with +backlog+, default is 1024.
252
+ # * Set up an SSL certificate with +key+ & +cert+.
253
+ # * Set whether to optimize for low latency instead of throughput with
254
+ # +low_latency+, default is to not optimize for low latency. This is done
255
+ # via +Socket::TCP_NODELAY+.
256
+ # * Set socket permissions with +umask+.
169
257
  #
170
258
  # @example Backlog depth
171
259
  # bind 'unix:///var/run/puma.sock?backlog=512'
@@ -175,6 +263,9 @@ module Puma
175
263
  # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
264
  # @example Socket permissions
177
265
  # bind 'unix:///var/run/puma.sock?umask=0111'
266
+ # @see Puma::Runner#load_and_bind
267
+ # @see Puma::Cluster#run
268
+ #
178
269
  def bind(url)
179
270
  @options[:binds] ||= []
180
271
  @options[:binds] << url
@@ -184,22 +275,49 @@ module Puma
184
275
  @options[:binds] = []
185
276
  end
186
277
 
278
+ # Bind to (systemd) activated sockets, regardless of configured binds.
279
+ #
280
+ # Systemd can present sockets as file descriptors that are already opened.
281
+ # By default Puma will use these but only if it was explicitly told to bind
282
+ # to the socket. If not, it will close the activated sockets. This means
283
+ # all configuration is duplicated.
284
+ #
285
+ # Binds can contain additional configuration, but only SSL config is really
286
+ # relevant since the unix and TCP socket options are ignored.
287
+ #
288
+ # This means there is a lot of duplicated configuration for no additional
289
+ # value in most setups. This method tells the launcher to bind to all
290
+ # activated sockets, regardless of existing bind.
291
+ #
292
+ # To clear configured binds, the value only can be passed. This will clear
293
+ # out any binds that may have been configured.
294
+ #
295
+ # @example Use any systemd activated sockets as well as configured binds
296
+ # bind_to_activated_sockets
297
+ #
298
+ # @example Only bind to systemd activated sockets, ignoring other binds
299
+ # bind_to_activated_sockets 'only'
300
+ def bind_to_activated_sockets(bind=true)
301
+ @options[:bind_to_activated_sockets] = bind
302
+ end
303
+
187
304
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
188
305
  #
189
306
  # @example
190
307
  # port 9292
191
308
  def port(port, host=nil)
192
309
  host ||= default_host
193
- bind "tcp://#{host}:#{port}"
310
+ bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
194
311
  end
195
312
 
196
- # Define how long persistent connections can be idle before Puma closes
197
- # them.
313
+ # Define how long persistent connections can be idle before Puma closes them.
314
+ # @see Puma::Server.new
198
315
  def persistent_timeout(seconds)
199
316
  @options[:persistent_timeout] = Integer(seconds)
200
317
  end
201
318
 
202
319
  # Define how long the tcp socket stays open, if no data has been received.
320
+ # @see Puma::Server.new
203
321
  def first_data_timeout(seconds)
204
322
  @options[:first_data_timeout] = Integer(seconds)
205
323
  end
@@ -210,24 +328,11 @@ module Puma
210
328
  @options[:clean_thread_locals] = which
211
329
  end
212
330
 
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
331
+ # When shutting down, drain the accept socket of pending connections and
332
+ # process them. This loops over the accept socket until there are no more
333
+ # read events and then stops looking and waits for the requests to finish.
334
+ # @see Puma::Server#graceful_shutdown
220
335
  #
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
336
  def drain_on_shutdown(which=true)
232
337
  @options[:drain_on_shutdown] = which
233
338
  end
@@ -250,6 +355,7 @@ module Puma
250
355
  #
251
356
  # Puma always waits a few seconds after killing a thread for it to try
252
357
  # to finish up it's work, even in :immediately mode.
358
+ # @see Puma::Server#graceful_shutdown
253
359
  def force_shutdown_after(val=:forever)
254
360
  i = case val
255
361
  when :forever
@@ -257,7 +363,7 @@ module Puma
257
363
  when :immediately
258
364
  0
259
365
  else
260
- Integer(val)
366
+ Float(val)
261
367
  end
262
368
 
263
369
  @options[:force_shutdown_after] = i
@@ -322,20 +428,21 @@ module Puma
322
428
  # @example
323
429
  # rackup '/u/apps/lolcat/config.ru'
324
430
  def rackup(path)
325
- @options[:rackup] = path.to_s
431
+ @options[:rackup] ||= path.to_s
326
432
  end
327
433
 
328
- # Run Puma in TCP mode
329
- #
330
- def tcp_mode!
331
- @options[:mode] = :tcp
434
+ # Allows setting `env['rack.url_scheme']`.
435
+ # Only necessary if X-Forwarded-Proto is not being set by your proxy
436
+ # Normal values are 'http' or 'https'.
437
+ def rack_url_scheme(scheme=nil)
438
+ @options[:rack_url_scheme] = scheme
332
439
  end
333
440
 
334
441
  def early_hints(answer=true)
335
442
  @options[:early_hints] = answer
336
443
  end
337
444
 
338
- # Redirect STDOUT and STDERR to files specified. The +append+ parameter
445
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
339
446
  # specifies whether the output is appended, the default is +false+.
340
447
  #
341
448
  # @example
@@ -355,7 +462,10 @@ module Puma
355
462
  # Configure +min+ to be the minimum number of threads to use to answer
356
463
  # requests and +max+ the maximum.
357
464
  #
358
- # The default is "0, 16".
465
+ # The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
466
+ # (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
467
+ #
468
+ # If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
359
469
  #
360
470
  # @example
361
471
  # threads 0, 16
@@ -376,8 +486,19 @@ module Puma
376
486
  @options[:max_threads] = max
377
487
  end
378
488
 
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.
489
+ # Instead of using +bind+ and manually constructing a URI like:
490
+ #
491
+ # bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
492
+ #
493
+ # you can use the this method.
494
+ #
495
+ # When binding on localhost you don't need to specify +cert+ and +key+,
496
+ # Puma will assume you are using the +localhost+ gem and try to load the
497
+ # appropriate files.
498
+ #
499
+ # When using the options hash parameter, the `reuse:` value is either
500
+ # `true`, which sets reuse 'on' with default values, or a hash, with `:size`
501
+ # and/or `:timeout` keys, each with integer values.
381
502
  #
382
503
  # @example
383
504
  # ssl_bind '127.0.0.1', '9292', {
@@ -385,29 +506,30 @@ module Puma
385
506
  # key: path_to_key,
386
507
  # ssl_cipher_filter: cipher_filter, # optional
387
508
  # verify_mode: verify_mode, # default 'none'
509
+ # verification_flags: flags, # optional, not supported by JRuby
510
+ # reuse: true # optional
388
511
  # }
389
- # @example For JRuby additional keys are required: keystore & keystore_pass.
512
+ #
513
+ # @example Using self-signed certificate with the +localhost+ gem:
514
+ # ssl_bind '127.0.0.1', '9292'
515
+ #
516
+ # @example Alternatively, you can provide +cert_pem+ and +key_pem+:
517
+ # ssl_bind '127.0.0.1', '9292', {
518
+ # cert_pem: File.read(path_to_cert),
519
+ # key_pem: File.read(path_to_key),
520
+ # reuse: {size: 2_000, timeout: 20} # optional
521
+ # }
522
+ #
523
+ # @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
390
524
  # 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
525
  # keystore: path_to_keystore,
396
- # keystore_pass: password
526
+ # keystore_pass: password,
527
+ # ssl_cipher_list: cipher_list, # optional
528
+ # verify_mode: verify_mode # default 'none'
397
529
  # }
398
- def ssl_bind(host, port, opts)
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)
403
-
404
- if defined?(JRUBY_VERSION)
405
- keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
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}"
407
- else
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}"
410
- end
530
+ def ssl_bind(host, port, opts = {})
531
+ add_pem_values_to_options_store(opts)
532
+ bind self.class.ssl_bind_str(host, port, opts)
411
533
  end
412
534
 
413
535
  # Use +path+ as the file to store the server info state. This is
@@ -419,16 +541,46 @@ module Puma
419
541
  @options[:state] = path.to_s
420
542
  end
421
543
 
544
+ # Use +permission+ to restrict permissions for the state file.
545
+ #
546
+ # @example
547
+ # state_permission 0600
548
+ # @version 5.0.0
549
+ #
550
+ def state_permission(permission)
551
+ @options[:state_permission] = permission
552
+ end
553
+
422
554
  # How many worker processes to run. Typically this is set to
423
- # to the number of available cores.
555
+ # the number of available cores.
424
556
  #
425
- # The default is 0.
557
+ # The default is the value of the environment variable +WEB_CONCURRENCY+ if
558
+ # set, otherwise 0.
426
559
  #
427
560
  # @note Cluster mode only.
561
+ # @see Puma::Cluster
428
562
  def workers(count)
429
563
  @options[:workers] = count.to_i
430
564
  end
431
565
 
566
+ # Disable warning message when running in cluster mode with a single worker.
567
+ #
568
+ # Cluster mode has some overhead of running an additional 'control' process
569
+ # in order to manage the cluster. If only running a single worker it is
570
+ # likely not worth paying that overhead vs running in single mode with
571
+ # additional threads instead.
572
+ #
573
+ # There are some scenarios where running cluster mode with a single worker
574
+ # may still be warranted and valid under certain deployment scenarios, see
575
+ # https://github.com/puma/puma/issues/2534
576
+ #
577
+ # Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
578
+ #
579
+ # @note Cluster mode only.
580
+ def silence_single_worker_warning
581
+ @options[:silence_single_worker_warning] = true
582
+ end
583
+
432
584
  # Code to run immediately before master process
433
585
  # forks workers (once on boot). These hooks can block if necessary
434
586
  # to wait for background operations unknown to Puma to finish before
@@ -455,12 +607,11 @@ module Puma
455
607
  #
456
608
  # @note Cluster mode only.
457
609
  # @example
458
- # on_worker_fork do
459
- # puts 'Before worker fork...'
610
+ # on_worker_boot do
611
+ # puts 'Before worker boot...'
460
612
  # end
461
- def on_worker_boot(&block)
462
- @options[:before_worker_boot] ||= []
463
- @options[:before_worker_boot] << block
613
+ def on_worker_boot(key = nil, &block)
614
+ process_hook :before_worker_boot, key, block, 'on_worker_boot'
464
615
  end
465
616
 
466
617
  # Code to run immediately before a worker shuts
@@ -475,9 +626,8 @@ module Puma
475
626
  # on_worker_shutdown do
476
627
  # puts 'On worker shutdown...'
477
628
  # end
478
- def on_worker_shutdown(&block)
479
- @options[:before_worker_shutdown] ||= []
480
- @options[:before_worker_shutdown] << block
629
+ def on_worker_shutdown(key = nil, &block)
630
+ process_hook :before_worker_shutdown, key, block, 'on_worker_shutdown'
481
631
  end
482
632
 
483
633
  # Code to run in the master right before a worker is started. The worker's
@@ -491,8 +641,7 @@ module Puma
491
641
  # puts 'Before worker fork...'
492
642
  # end
493
643
  def on_worker_fork(&block)
494
- @options[:before_worker_fork] ||= []
495
- @options[:before_worker_fork] << block
644
+ process_hook :before_worker_fork, nil, block, 'on_worker_fork'
496
645
  end
497
646
 
498
647
  # Code to run in the master after a worker has been started. The worker's
@@ -506,12 +655,33 @@ module Puma
506
655
  # puts 'After worker fork...'
507
656
  # end
508
657
  def after_worker_fork(&block)
509
- @options[:after_worker_fork] ||= []
510
- @options[:after_worker_fork] = block
658
+ process_hook :after_worker_fork, nil, block, 'after_worker_fork'
511
659
  end
512
660
 
513
661
  alias_method :after_worker_boot, :after_worker_fork
514
662
 
663
+ # When `fork_worker` is enabled, code to run in Worker 0
664
+ # before all other workers are re-forked from this process,
665
+ # after the server has temporarily stopped serving requests
666
+ # (once per complete refork cycle).
667
+ #
668
+ # This can be used to trigger extra garbage-collection to maximize
669
+ # copy-on-write efficiency, or close any connections to remote servers
670
+ # (database, Redis, ...) that were opened while the server was running.
671
+ #
672
+ # This can be called multiple times to add several hooks.
673
+ #
674
+ # @note Cluster mode with `fork_worker` enabled only.
675
+ # @example
676
+ # on_refork do
677
+ # 3.times {GC.start}
678
+ # end
679
+ # @version 5.0.0
680
+ #
681
+ def on_refork(key = nil, &block)
682
+ process_hook :before_refork, key, block, 'on_refork'
683
+ end
684
+
515
685
  # Code to run out-of-band when the worker is idle.
516
686
  # These hooks run immediately after a request has finished
517
687
  # processing and there are no busy threads on the worker.
@@ -522,8 +692,7 @@ module Puma
522
692
  #
523
693
  # This can be called multiple times to add several hooks.
524
694
  def out_of_band(&block)
525
- @options[:out_of_band] ||= []
526
- @options[:out_of_band] << block
695
+ process_hook :out_of_band, nil, block, 'out_of_band'
527
696
  end
528
697
 
529
698
  # The directory to operate out of.
@@ -536,19 +705,8 @@ module Puma
536
705
  @options[:directory] = dir.to_s
537
706
  end
538
707
 
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
708
  # Preload the application before starting the workers; this conflicts with
551
- # phased restart feature. This is off by default.
709
+ # phased restart feature. On by default if your app uses more than 1 worker.
552
710
  #
553
711
  # @note Cluster mode only.
554
712
  # @example
@@ -583,7 +741,7 @@ module Puma
583
741
  # new Bundler context and thus can float around as the release
584
742
  # dictates.
585
743
  #
586
- # See also: extra_runtime_dependencies
744
+ # @see extra_runtime_dependencies
587
745
  #
588
746
  # @note This is incompatible with +preload_app!+.
589
747
  # @note This is only supported for RubyGems 2.2+
@@ -600,6 +758,9 @@ module Puma
600
758
  #
601
759
  # @example
602
760
  # raise_exception_on_sigterm false
761
+ # @see Puma::Launcher#setup_signals
762
+ # @see Puma::Cluster#setup_signals
763
+ #
603
764
  def raise_exception_on_sigterm(answer=true)
604
765
  @options[:raise_exception_on_sigterm] = answer
605
766
  end
@@ -615,6 +776,8 @@ module Puma
615
776
  # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
616
777
  # @example
617
778
  # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
779
+ # @see Puma::Launcher#extra_runtime_deps_directories
780
+ #
618
781
  def extra_runtime_dependencies(answer = [])
619
782
  @options[:extra_runtime_dependencies] = Array(answer)
620
783
  end
@@ -632,6 +795,19 @@ module Puma
632
795
  @options[:tag] = string.to_s
633
796
  end
634
797
 
798
+ # Change the default interval for checking workers.
799
+ #
800
+ # The default value is 5 seconds.
801
+ #
802
+ # @note Cluster mode only.
803
+ # @example
804
+ # worker_check_interval 5
805
+ # @see Puma::Cluster#check_workers
806
+ #
807
+ def worker_check_interval(interval)
808
+ @options[:worker_check_interval] = Integer(interval)
809
+ end
810
+
635
811
  # Verifies that all workers have checked in to the master process within
636
812
  # the given timeout. If not the worker process will be restarted. This is
637
813
  # not a request timeout, it is to protect against a hung or dead process.
@@ -642,9 +818,11 @@ module Puma
642
818
  # @note Cluster mode only.
643
819
  # @example
644
820
  # worker_timeout 60
821
+ # @see Puma::Cluster::Worker#ping_timeout
822
+ #
645
823
  def worker_timeout(timeout)
646
824
  timeout = Integer(timeout)
647
- min = Const::WORKER_CHECK_INTERVAL
825
+ min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
648
826
 
649
827
  if timeout <= min
650
828
  raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
@@ -658,19 +836,48 @@ module Puma
658
836
  # If unspecified, this defaults to the value of worker_timeout.
659
837
  #
660
838
  # @note Cluster mode only.
661
- # @example:
839
+ #
840
+ # @example
662
841
  # worker_boot_timeout 60
842
+ # @see Puma::Cluster::Worker#ping_timeout
843
+ #
663
844
  def worker_boot_timeout(timeout)
664
845
  @options[:worker_boot_timeout] = Integer(timeout)
665
846
  end
666
847
 
667
- # Set the timeout for worker shutdown
848
+ # Set the timeout for worker shutdown.
668
849
  #
669
850
  # @note Cluster mode only.
851
+ # @see Puma::Cluster::Worker#term
852
+ #
670
853
  def worker_shutdown_timeout(timeout)
671
854
  @options[:worker_shutdown_timeout] = Integer(timeout)
672
855
  end
673
856
 
857
+ # Set the strategy for worker culling.
858
+ #
859
+ # There are two possible values:
860
+ #
861
+ # 1. **:youngest** - the youngest workers (i.e. the workers that were
862
+ # the most recently started) will be culled.
863
+ # 2. **:oldest** - the oldest workers (i.e. the workers that were started
864
+ # the longest time ago) will be culled.
865
+ #
866
+ # @note Cluster mode only.
867
+ # @example
868
+ # worker_culling_strategy :oldest
869
+ # @see Puma::Cluster#cull_workers
870
+ #
871
+ def worker_culling_strategy(strategy)
872
+ stategy = strategy.to_sym
873
+
874
+ if ![:youngest, :oldest].include?(strategy)
875
+ raise "Invalid value for worker_culling_strategy - #{stategy}"
876
+ end
877
+
878
+ @options[:worker_culling_strategy] = strategy
879
+ end
880
+
674
881
  # When set to true (the default), workers accept all requests
675
882
  # and queue them before passing them to the handlers.
676
883
  # When set to false, each worker process accepts exactly as
@@ -684,6 +891,7 @@ module Puma
684
891
  # slow clients will occupy a handler thread while the request
685
892
  # is being sent. A reverse proxy, such as nginx, can handle
686
893
  # slow clients and queue requests before they reach Puma.
894
+ # @see Puma::Server
687
895
  def queue_requests(answer=true)
688
896
  @options[:queue_requests] = answer
689
897
  end
@@ -691,29 +899,50 @@ module Puma
691
899
  # When a shutdown is requested, the backtraces of all the
692
900
  # threads will be written to $stdout. This can help figure
693
901
  # out why shutdown is hanging.
902
+ #
694
903
  def shutdown_debug(val=true)
695
904
  @options[:shutdown_debug] = val
696
905
  end
697
906
 
907
+
908
+ # Attempts to route traffic to less-busy workers by causing them to delay
909
+ # listening on the socket, allowing workers which are not processing any
910
+ # requests to pick up new requests first.
911
+ #
912
+ # Only works on MRI. For all other interpreters, this setting does nothing.
913
+ # @see Puma::Server#handle_servers
914
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
915
+ # @version 5.0.0
916
+ #
917
+ def wait_for_less_busy_worker(val=0.005)
918
+ @options[:wait_for_less_busy_worker] = val.to_f
919
+ end
920
+
698
921
  # Control how the remote address of the connection is set. This
699
922
  # is configurable because to calculate the true socket peer address
700
923
  # a kernel syscall is required which for very fast rack handlers
701
924
  # slows down the handling significantly.
702
925
  #
703
- # There are 4 possible values:
704
- #
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.
926
+ # There are 5 possible values:
927
+ #
928
+ # 1. **:socket** (the default) - read the peername from the socket using the
929
+ # syscall. This is the normal behavior. If this fails for any reason (e.g.,
930
+ # if the peer disconnects between the connection being accepted and the getpeername
931
+ # system call), Puma will return "0.0.0.0"
932
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
933
+ # 3. **header: <http_header>**- set the remote address to the value of the
934
+ # provided http header. For instance:
935
+ # `set_remote_address header: "X-Real-IP"`.
936
+ # Only the first word (as separated by spaces or comma) is used, allowing
937
+ # headers such as X-Forwarded-For to be used as well. If this header is absent,
938
+ # Puma will fall back to the behavior of :socket
939
+ # 4. **proxy_protocol: :v1**- set the remote address to the value read from the
940
+ # HAproxy PROXY protocol, version 1. If the request does not have the PROXY
941
+ # protocol attached to it, will fall back to :socket
942
+ # 5. **\<Any string\>** - this allows you to hardcode remote address to any value
943
+ # you wish. Because Puma never uses this field anyway, it's format is
944
+ # entirely in your hands.
945
+ #
717
946
  def set_remote_address(val=:socket)
718
947
  case val
719
948
  when :socket
@@ -728,6 +957,13 @@ module Puma
728
957
  if hdr = val[:header]
729
958
  @options[:remote_address] = :header
730
959
  @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
960
+ elsif protocol_version = val[:proxy_protocol]
961
+ @options[:remote_address] = :proxy_protocol
962
+ protocol_version = protocol_version.downcase.to_sym
963
+ unless [:v1].include?(protocol_version)
964
+ raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
965
+ end
966
+ @options[:remote_address_proxy_protocol] = protocol_version
731
967
  else
732
968
  raise "Invalid value for set_remote_address - #{val.inspect}"
733
969
  end
@@ -736,5 +972,82 @@ module Puma
736
972
  end
737
973
  end
738
974
 
975
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
976
+ # This option is similar to `preload_app` because the app is preloaded before forking,
977
+ # but it is compatible with phased restart.
978
+ #
979
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
980
+ # in a running app.
981
+ #
982
+ # A refork will automatically trigger once after the specified number of requests
983
+ # (default 1000), or pass 0 to disable auto refork.
984
+ #
985
+ # @note Cluster mode only.
986
+ # @version 5.0.0
987
+ #
988
+ def fork_worker(after_requests=1000)
989
+ @options[:fork_worker] = Integer(after_requests)
990
+ end
991
+
992
+ # The number of requests to attempt inline before sending a client back to
993
+ # the reactor to be subject to normal ordering.
994
+ #
995
+ def max_fast_inline(num_of_requests)
996
+ @options[:max_fast_inline] = Float(num_of_requests)
997
+ end
998
+
999
+ # Specify the backend for the IO selector.
1000
+ #
1001
+ # Provided values will be passed directly to +NIO::Selector.new+, with the
1002
+ # exception of +:auto+ which will let nio4r choose the backend.
1003
+ #
1004
+ # Check the documentation of +NIO::Selector.backends+ for the list of valid
1005
+ # options. Note that the available options on your system will depend on the
1006
+ # operating system. If you want to use the pure Ruby backend (not
1007
+ # recommended due to its comparatively low performance), set environment
1008
+ # variable +NIO4R_PURE+ to +true+.
1009
+ #
1010
+ # The default is +:auto+.
1011
+ #
1012
+ # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
1013
+ #
1014
+ def io_selector_backend(backend)
1015
+ @options[:io_selector_backend] = backend.to_sym
1016
+ end
1017
+
1018
+ def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
1019
+ @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
1020
+ end
1021
+
1022
+ private
1023
+
1024
+ # To avoid adding cert_pem and key_pem as URI params, we store them on the
1025
+ # options[:store] from where Puma binder knows how to find and extract them.
1026
+ def add_pem_values_to_options_store(opts)
1027
+ return if defined?(JRUBY_VERSION)
1028
+
1029
+ @options[:store] ||= []
1030
+
1031
+ # Store cert_pem and key_pem to options[:store] if present
1032
+ [:cert, :key].each do |v|
1033
+ opt_key = :"#{v}_pem"
1034
+ if opts[opt_key]
1035
+ index = @options[:store].length
1036
+ @options[:store] << opts[opt_key]
1037
+ opts[v] = "store:#{index}"
1038
+ end
1039
+ end
1040
+ end
1041
+
1042
+ def process_hook(options_key, key, block, meth)
1043
+ @options[options_key] ||= []
1044
+ if ON_WORKER_KEY.include? key.class
1045
+ @options[options_key] << [block, key.to_sym]
1046
+ elsif key.nil?
1047
+ @options[options_key] << block
1048
+ else
1049
+ raise "'#{method}' key must be String or Symbol"
1050
+ end
1051
+ end
739
1052
  end
740
1053
  end