puma 4.3.12 → 5.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1526 -524
  3. data/LICENSE +23 -20
  4. data/README.md +120 -36
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +21 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +33 -0
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +9 -0
  14. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  15. data/{tools → docs}/jungle/rc.d/puma +2 -2
  16. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +66 -0
  18. data/docs/nginx.md +1 -1
  19. data/docs/plugins.md +15 -15
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +46 -23
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +85 -128
  25. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  26. data/ext/puma_http11/ext_help.h +1 -1
  27. data/ext/puma_http11/extconf.rb +44 -10
  28. data/ext/puma_http11/http11_parser.c +45 -47
  29. data/ext/puma_http11/http11_parser.h +1 -1
  30. data/ext/puma_http11/http11_parser.java.rl +1 -1
  31. data/ext/puma_http11/http11_parser.rl +1 -1
  32. data/ext/puma_http11/http11_parser_common.rl +0 -0
  33. data/ext/puma_http11/mini_ssl.c +225 -89
  34. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  35. data/ext/puma_http11/org/jruby/puma/Http11.java +5 -3
  36. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +3 -5
  37. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +109 -67
  38. data/ext/puma_http11/puma_http11.c +32 -51
  39. data/lib/puma/app/status.rb +50 -36
  40. data/lib/puma/binder.rb +225 -106
  41. data/lib/puma/cli.rb +24 -18
  42. data/lib/puma/client.rb +146 -84
  43. data/lib/puma/cluster/worker.rb +173 -0
  44. data/lib/puma/cluster/worker_handle.rb +94 -0
  45. data/lib/puma/cluster.rb +212 -220
  46. data/lib/puma/commonlogger.rb +2 -2
  47. data/lib/puma/configuration.rb +58 -49
  48. data/lib/puma/const.rb +22 -7
  49. data/lib/puma/control_cli.rb +99 -76
  50. data/lib/puma/detect.rb +29 -2
  51. data/lib/puma/dsl.rb +368 -96
  52. data/lib/puma/error_logger.rb +104 -0
  53. data/lib/puma/events.rb +55 -34
  54. data/lib/puma/io_buffer.rb +9 -2
  55. data/lib/puma/jruby_restart.rb +0 -58
  56. data/lib/puma/json_serialization.rb +96 -0
  57. data/lib/puma/launcher.rb +128 -46
  58. data/lib/puma/minissl/context_builder.rb +14 -9
  59. data/lib/puma/minissl.rb +137 -50
  60. data/lib/puma/null_io.rb +18 -1
  61. data/lib/puma/plugin/tmp_restart.rb +0 -0
  62. data/lib/puma/plugin.rb +3 -12
  63. data/lib/puma/queue_close.rb +26 -0
  64. data/lib/puma/rack/builder.rb +1 -5
  65. data/lib/puma/rack/urlmap.rb +0 -0
  66. data/lib/puma/rack_default.rb +0 -0
  67. data/lib/puma/reactor.rb +85 -369
  68. data/lib/puma/request.rb +489 -0
  69. data/lib/puma/runner.rb +46 -61
  70. data/lib/puma/server.rb +292 -763
  71. data/lib/puma/single.rb +9 -65
  72. data/lib/puma/state_file.rb +48 -8
  73. data/lib/puma/systemd.rb +46 -0
  74. data/lib/puma/thread_pool.rb +125 -57
  75. data/lib/puma/util.rb +32 -4
  76. data/lib/puma.rb +48 -0
  77. data/lib/rack/handler/puma.rb +2 -3
  78. data/lib/rack/version_restriction.rb +15 -0
  79. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  80. data/tools/trickletest.rb +0 -0
  81. metadata +29 -24
  82. data/docs/tcp_mode.md +0 -96
  83. data/ext/puma_http11/io_buffer.c +0 -155
  84. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  85. data/lib/puma/accept_nonblock.rb +0 -29
  86. data/lib/puma/tcp_logger.rb +0 -41
  87. data/tools/jungle/README.md +0 -19
  88. data/tools/jungle/init.d/README.md +0 -61
  89. data/tools/jungle/init.d/puma +0 -421
  90. data/tools/jungle/init.d/run-puma +0 -18
  91. data/tools/jungle/upstart/README.md +0 -61
  92. data/tools/jungle/upstart/puma-manager.conf +0 -31
  93. 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
3
  require 'puma/const'
4
+ require 'puma/util'
4
5
 
5
6
  module Puma
6
7
  # The methods that are available for use inside the configuration file.
@@ -14,25 +15,65 @@ 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
+ #
33
35
  class DSL
34
36
  include ConfigDefault
35
37
 
38
+ # convenience method so logic can be used in CI
39
+ # @see ssl_bind
40
+ #
41
+ def self.ssl_bind_str(host, port, opts)
42
+ verify = opts.fetch(:verify_mode, 'none').to_s
43
+
44
+ tls_str =
45
+ if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
46
+ elsif opts[:no_tlsv1] then '&no_tlsv1=true'
47
+ else ''
48
+ end
49
+
50
+ ca_additions = "&ca=#{Puma::Util.escape(opts[:ca])}" if ['peer', 'force_peer'].include?(verify)
51
+
52
+ backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
53
+
54
+ if defined?(JRUBY_VERSION)
55
+ ssl_cipher_list = opts[:ssl_cipher_list] ?
56
+ "&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
57
+
58
+ keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
59
+
60
+ "ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
61
+ "&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
62
+ else
63
+ ssl_cipher_filter = opts[:ssl_cipher_filter] ?
64
+ "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
65
+
66
+ v_flags = (ary = opts[:verification_flags]) ?
67
+ "&verification_flags=#{Array(ary).join ','}" : nil
68
+
69
+ cert_flags = (cert = opts[:cert]) ? "cert=#{Puma::Util.escape(opts[:cert])}" : nil
70
+ key_flags = (cert = opts[:key]) ? "&key=#{Puma::Util.escape(opts[:key])}" : nil
71
+
72
+ "ssl://#{host}:#{port}?#{cert_flags}#{key_flags}" \
73
+ "#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
74
+ end
75
+ end
76
+
36
77
  def initialize(options, config)
37
78
  @config = config
38
79
  @options = options
@@ -98,6 +139,9 @@ module Puma
98
139
  # [body]
99
140
  # ]
100
141
  # end
142
+ #
143
+ # @see Puma::Configuration#app
144
+ #
101
145
  def app(obj=nil, &block)
102
146
  obj ||= block
103
147
 
@@ -153,19 +197,19 @@ module Puma
153
197
  end
154
198
 
155
199
  # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
156
- # accepted protocols. Multiple urls can be bound to, calling `bind` does
200
+ # accepted protocols. Multiple urls can be bound to, calling +bind+ does
157
201
  # not overwrite previous bindings.
158
202
  #
159
203
  # The default is "tcp://0.0.0.0:9292".
160
204
  #
161
205
  # You can use query parameters within the url to specify options:
162
206
  #
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+.
207
+ # * Set the socket backlog depth with +backlog+, default is 1024.
208
+ # * Set up an SSL certificate with +key+ & +cert+.
209
+ # * Set whether to optimize for low latency instead of throughput with
210
+ # +low_latency+, default is to not optimize for low latency. This is done
211
+ # via +Socket::TCP_NODELAY+.
212
+ # * Set socket permissions with +umask+.
169
213
  #
170
214
  # @example Backlog depth
171
215
  # bind 'unix:///var/run/puma.sock?backlog=512'
@@ -175,6 +219,9 @@ module Puma
175
219
  # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
220
  # @example Socket permissions
177
221
  # bind 'unix:///var/run/puma.sock?umask=0111'
222
+ # @see Puma::Runner#load_and_bind
223
+ # @see Puma::Cluster#run
224
+ #
178
225
  def bind(url)
179
226
  @options[:binds] ||= []
180
227
  @options[:binds] << url
@@ -184,22 +231,49 @@ module Puma
184
231
  @options[:binds] = []
185
232
  end
186
233
 
234
+ # Bind to (systemd) activated sockets, regardless of configured binds.
235
+ #
236
+ # Systemd can present sockets as file descriptors that are already opened.
237
+ # By default Puma will use these but only if it was explicitly told to bind
238
+ # to the socket. If not, it will close the activated sockets. This means
239
+ # all configuration is duplicated.
240
+ #
241
+ # Binds can contain additional configuration, but only SSL config is really
242
+ # relevant since the unix and TCP socket options are ignored.
243
+ #
244
+ # This means there is a lot of duplicated configuration for no additional
245
+ # value in most setups. This method tells the launcher to bind to all
246
+ # activated sockets, regardless of existing bind.
247
+ #
248
+ # To clear configured binds, the value only can be passed. This will clear
249
+ # out any binds that may have been configured.
250
+ #
251
+ # @example Use any systemd activated sockets as well as configured binds
252
+ # bind_to_activated_sockets
253
+ #
254
+ # @example Only bind to systemd activated sockets, ignoring other binds
255
+ # bind_to_activated_sockets 'only'
256
+ def bind_to_activated_sockets(bind=true)
257
+ @options[:bind_to_activated_sockets] = bind
258
+ end
259
+
187
260
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
188
261
  #
189
262
  # @example
190
263
  # port 9292
191
264
  def port(port, host=nil)
192
265
  host ||= default_host
193
- bind "tcp://#{host}:#{port}"
266
+ bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
194
267
  end
195
268
 
196
- # Define how long persistent connections can be idle before Puma closes
197
- # them.
269
+ # Define how long persistent connections can be idle before Puma closes them.
270
+ # @see Puma::Server.new
198
271
  def persistent_timeout(seconds)
199
272
  @options[:persistent_timeout] = Integer(seconds)
200
273
  end
201
274
 
202
275
  # Define how long the tcp socket stays open, if no data has been received.
276
+ # @see Puma::Server.new
203
277
  def first_data_timeout(seconds)
204
278
  @options[:first_data_timeout] = Integer(seconds)
205
279
  end
@@ -210,24 +284,11 @@ module Puma
210
284
  @options[:clean_thread_locals] = which
211
285
  end
212
286
 
213
- # Daemonize the server into the background. It's highly recommended to
214
- # use this in combination with +pidfile+ and +stdout_redirect+.
287
+ # When shutting down, drain the accept socket of pending connections and
288
+ # process them. This loops over the accept socket until there are no more
289
+ # read events and then stops looking and waits for the requests to finish.
290
+ # @see Puma::Server#graceful_shutdown
215
291
  #
216
- # The default is "false".
217
- #
218
- # @example
219
- # daemonize
220
- #
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
292
  def drain_on_shutdown(which=true)
232
293
  @options[:drain_on_shutdown] = which
233
294
  end
@@ -250,6 +311,7 @@ module Puma
250
311
  #
251
312
  # Puma always waits a few seconds after killing a thread for it to try
252
313
  # to finish up it's work, even in :immediately mode.
314
+ # @see Puma::Server#graceful_shutdown
253
315
  def force_shutdown_after(val=:forever)
254
316
  i = case val
255
317
  when :forever
@@ -257,7 +319,7 @@ module Puma
257
319
  when :immediately
258
320
  0
259
321
  else
260
- Integer(val)
322
+ Float(val)
261
323
  end
262
324
 
263
325
  @options[:force_shutdown_after] = i
@@ -322,20 +384,21 @@ module Puma
322
384
  # @example
323
385
  # rackup '/u/apps/lolcat/config.ru'
324
386
  def rackup(path)
325
- @options[:rackup] = path.to_s
387
+ @options[:rackup] ||= path.to_s
326
388
  end
327
389
 
328
- # Run Puma in TCP mode
329
- #
330
- def tcp_mode!
331
- @options[:mode] = :tcp
390
+ # Allows setting `env['rack.url_scheme']`.
391
+ # Only necessary if X-Forwarded-Proto is not being set by your proxy
392
+ # Normal values are 'http' or 'https'.
393
+ def rack_url_scheme(scheme=nil)
394
+ @options[:rack_url_scheme] = scheme
332
395
  end
333
396
 
334
397
  def early_hints(answer=true)
335
398
  @options[:early_hints] = answer
336
399
  end
337
400
 
338
- # Redirect STDOUT and STDERR to files specified. The +append+ parameter
401
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
339
402
  # specifies whether the output is appended, the default is +false+.
340
403
  #
341
404
  # @example
@@ -355,7 +418,10 @@ module Puma
355
418
  # Configure +min+ to be the minimum number of threads to use to answer
356
419
  # requests and +max+ the maximum.
357
420
  #
358
- # The default is "0, 16".
421
+ # The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
422
+ # (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
423
+ #
424
+ # If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
359
425
  #
360
426
  # @example
361
427
  # threads 0, 16
@@ -376,8 +442,15 @@ module Puma
376
442
  @options[:max_threads] = max
377
443
  end
378
444
 
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.
445
+ # Instead of using +bind+ and manually constructing a URI like:
446
+ #
447
+ # bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
448
+ #
449
+ # you can use the this method.
450
+ #
451
+ # When binding on localhost you don't need to specify +cert+ and +key+,
452
+ # Puma will assume you are using the +localhost+ gem and try to load the
453
+ # appropriate files.
381
454
  #
382
455
  # @example
383
456
  # ssl_bind '127.0.0.1', '9292', {
@@ -385,29 +458,28 @@ module Puma
385
458
  # key: path_to_key,
386
459
  # ssl_cipher_filter: cipher_filter, # optional
387
460
  # verify_mode: verify_mode, # default 'none'
461
+ # verification_flags: flags, # optional, not supported by JRuby
388
462
  # }
389
- # @example For JRuby additional keys are required: keystore & keystore_pass.
463
+ #
464
+ # @example Using self-signed certificate with the +localhost+ gem:
465
+ # ssl_bind '127.0.0.1', '9292'
466
+ #
467
+ # @example Alternatively, you can provide +cert_pem+ and +key_pem+:
468
+ # ssl_bind '127.0.0.1', '9292', {
469
+ # cert_pem: File.read(path_to_cert),
470
+ # key_pem: File.read(path_to_key),
471
+ # }
472
+ #
473
+ # @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
390
474
  # 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
475
  # keystore: path_to_keystore,
396
- # keystore_pass: password
476
+ # keystore_pass: password,
477
+ # ssl_cipher_list: cipher_list, # optional
478
+ # verify_mode: verify_mode # default 'none'
397
479
  # }
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
480
+ def ssl_bind(host, port, opts = {})
481
+ add_pem_values_to_options_store(opts)
482
+ bind self.class.ssl_bind_str(host, port, opts)
411
483
  end
412
484
 
413
485
  # Use +path+ as the file to store the server info state. This is
@@ -419,16 +491,46 @@ module Puma
419
491
  @options[:state] = path.to_s
420
492
  end
421
493
 
494
+ # Use +permission+ to restrict permissions for the state file.
495
+ #
496
+ # @example
497
+ # state_permission 0600
498
+ # @version 5.0.0
499
+ #
500
+ def state_permission(permission)
501
+ @options[:state_permission] = permission
502
+ end
503
+
422
504
  # How many worker processes to run. Typically this is set to
423
- # to the number of available cores.
505
+ # the number of available cores.
424
506
  #
425
- # The default is 0.
507
+ # The default is the value of the environment variable +WEB_CONCURRENCY+ if
508
+ # set, otherwise 0.
426
509
  #
427
510
  # @note Cluster mode only.
511
+ # @see Puma::Cluster
428
512
  def workers(count)
429
513
  @options[:workers] = count.to_i
430
514
  end
431
515
 
516
+ # Disable warning message when running in cluster mode with a single worker.
517
+ #
518
+ # Cluster mode has some overhead of running an additional 'control' process
519
+ # in order to manage the cluster. If only running a single worker it is
520
+ # likely not worth paying that overhead vs running in single mode with
521
+ # additional threads instead.
522
+ #
523
+ # There are some scenarios where running cluster mode with a single worker
524
+ # may still be warranted and valid under certain deployment scenarios, see
525
+ # https://github.com/puma/puma/issues/2534
526
+ #
527
+ # Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
528
+ #
529
+ # @note Cluster mode only.
530
+ def silence_single_worker_warning
531
+ @options[:silence_single_worker_warning] = true
532
+ end
533
+
432
534
  # Code to run immediately before master process
433
535
  # forks workers (once on boot). These hooks can block if necessary
434
536
  # to wait for background operations unknown to Puma to finish before
@@ -455,8 +557,8 @@ module Puma
455
557
  #
456
558
  # @note Cluster mode only.
457
559
  # @example
458
- # on_worker_fork do
459
- # puts 'Before worker fork...'
560
+ # on_worker_boot do
561
+ # puts 'Before worker boot...'
460
562
  # end
461
563
  def on_worker_boot(&block)
462
564
  @options[:before_worker_boot] ||= []
@@ -507,11 +609,34 @@ module Puma
507
609
  # end
508
610
  def after_worker_fork(&block)
509
611
  @options[:after_worker_fork] ||= []
510
- @options[:after_worker_fork] = block
612
+ @options[:after_worker_fork] << block
511
613
  end
512
614
 
513
615
  alias_method :after_worker_boot, :after_worker_fork
514
616
 
617
+ # When `fork_worker` is enabled, code to run in Worker 0
618
+ # before all other workers are re-forked from this process,
619
+ # after the server has temporarily stopped serving requests
620
+ # (once per complete refork cycle).
621
+ #
622
+ # This can be used to trigger extra garbage-collection to maximize
623
+ # copy-on-write efficiency, or close any connections to remote servers
624
+ # (database, Redis, ...) that were opened while the server was running.
625
+ #
626
+ # This can be called multiple times to add several hooks.
627
+ #
628
+ # @note Cluster mode with `fork_worker` enabled only.
629
+ # @example
630
+ # on_refork do
631
+ # 3.times {GC.start}
632
+ # end
633
+ # @version 5.0.0
634
+ #
635
+ def on_refork(&block)
636
+ @options[:before_refork] ||= []
637
+ @options[:before_refork] << block
638
+ end
639
+
515
640
  # Code to run out-of-band when the worker is idle.
516
641
  # These hooks run immediately after a request has finished
517
642
  # processing and there are no busy threads on the worker.
@@ -536,19 +661,8 @@ module Puma
536
661
  @options[:directory] = dir.to_s
537
662
  end
538
663
 
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
664
  # Preload the application before starting the workers; this conflicts with
551
- # phased restart feature. This is off by default.
665
+ # phased restart feature. On by default if your app uses more than 1 worker.
552
666
  #
553
667
  # @note Cluster mode only.
554
668
  # @example
@@ -583,7 +697,7 @@ module Puma
583
697
  # new Bundler context and thus can float around as the release
584
698
  # dictates.
585
699
  #
586
- # See also: extra_runtime_dependencies
700
+ # @see extra_runtime_dependencies
587
701
  #
588
702
  # @note This is incompatible with +preload_app!+.
589
703
  # @note This is only supported for RubyGems 2.2+
@@ -600,6 +714,9 @@ module Puma
600
714
  #
601
715
  # @example
602
716
  # raise_exception_on_sigterm false
717
+ # @see Puma::Launcher#setup_signals
718
+ # @see Puma::Cluster#setup_signals
719
+ #
603
720
  def raise_exception_on_sigterm(answer=true)
604
721
  @options[:raise_exception_on_sigterm] = answer
605
722
  end
@@ -615,6 +732,8 @@ module Puma
615
732
  # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
616
733
  # @example
617
734
  # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
735
+ # @see Puma::Launcher#extra_runtime_deps_directories
736
+ #
618
737
  def extra_runtime_dependencies(answer = [])
619
738
  @options[:extra_runtime_dependencies] = Array(answer)
620
739
  end
@@ -632,6 +751,19 @@ module Puma
632
751
  @options[:tag] = string.to_s
633
752
  end
634
753
 
754
+ # Change the default interval for checking workers.
755
+ #
756
+ # The default value is 5 seconds.
757
+ #
758
+ # @note Cluster mode only.
759
+ # @example
760
+ # worker_check_interval 5
761
+ # @see Puma::Cluster#check_workers
762
+ #
763
+ def worker_check_interval(interval)
764
+ @options[:worker_check_interval] = Integer(interval)
765
+ end
766
+
635
767
  # Verifies that all workers have checked in to the master process within
636
768
  # the given timeout. If not the worker process will be restarted. This is
637
769
  # not a request timeout, it is to protect against a hung or dead process.
@@ -642,9 +774,11 @@ module Puma
642
774
  # @note Cluster mode only.
643
775
  # @example
644
776
  # worker_timeout 60
777
+ # @see Puma::Cluster::Worker#ping_timeout
778
+ #
645
779
  def worker_timeout(timeout)
646
780
  timeout = Integer(timeout)
647
- min = Const::WORKER_CHECK_INTERVAL
781
+ min = @options.fetch(:worker_check_interval, Puma::ConfigDefault::DefaultWorkerCheckInterval)
648
782
 
649
783
  if timeout <= min
650
784
  raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
@@ -658,19 +792,48 @@ module Puma
658
792
  # If unspecified, this defaults to the value of worker_timeout.
659
793
  #
660
794
  # @note Cluster mode only.
661
- # @example:
795
+ #
796
+ # @example
662
797
  # worker_boot_timeout 60
798
+ # @see Puma::Cluster::Worker#ping_timeout
799
+ #
663
800
  def worker_boot_timeout(timeout)
664
801
  @options[:worker_boot_timeout] = Integer(timeout)
665
802
  end
666
803
 
667
- # Set the timeout for worker shutdown
804
+ # Set the timeout for worker shutdown.
668
805
  #
669
806
  # @note Cluster mode only.
807
+ # @see Puma::Cluster::Worker#term
808
+ #
670
809
  def worker_shutdown_timeout(timeout)
671
810
  @options[:worker_shutdown_timeout] = Integer(timeout)
672
811
  end
673
812
 
813
+ # Set the strategy for worker culling.
814
+ #
815
+ # There are two possible values:
816
+ #
817
+ # 1. **:youngest** - the youngest workers (i.e. the workers that were
818
+ # the most recently started) will be culled.
819
+ # 2. **:oldest** - the oldest workers (i.e. the workers that were started
820
+ # the longest time ago) will be culled.
821
+ #
822
+ # @note Cluster mode only.
823
+ # @example
824
+ # worker_culling_strategy :oldest
825
+ # @see Puma::Cluster#cull_workers
826
+ #
827
+ def worker_culling_strategy(strategy)
828
+ stategy = strategy.to_sym
829
+
830
+ if ![:youngest, :oldest].include?(strategy)
831
+ raise "Invalid value for worker_culling_strategy - #{stategy}"
832
+ end
833
+
834
+ @options[:worker_culling_strategy] = strategy
835
+ end
836
+
674
837
  # When set to true (the default), workers accept all requests
675
838
  # and queue them before passing them to the handlers.
676
839
  # When set to false, each worker process accepts exactly as
@@ -684,6 +847,7 @@ module Puma
684
847
  # slow clients will occupy a handler thread while the request
685
848
  # is being sent. A reverse proxy, such as nginx, can handle
686
849
  # slow clients and queue requests before they reach Puma.
850
+ # @see Puma::Server
687
851
  def queue_requests(answer=true)
688
852
  @options[:queue_requests] = answer
689
853
  end
@@ -691,29 +855,47 @@ module Puma
691
855
  # When a shutdown is requested, the backtraces of all the
692
856
  # threads will be written to $stdout. This can help figure
693
857
  # out why shutdown is hanging.
858
+ #
694
859
  def shutdown_debug(val=true)
695
860
  @options[:shutdown_debug] = val
696
861
  end
697
862
 
863
+
864
+ # Attempts to route traffic to less-busy workers by causing them to delay
865
+ # listening on the socket, allowing workers which are not processing any
866
+ # requests to pick up new requests first.
867
+ #
868
+ # Only works on MRI. For all other interpreters, this setting does nothing.
869
+ # @see Puma::Server#handle_servers
870
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
871
+ # @version 5.0.0
872
+ #
873
+ def wait_for_less_busy_worker(val=0.005)
874
+ @options[:wait_for_less_busy_worker] = val.to_f
875
+ end
876
+
698
877
  # Control how the remote address of the connection is set. This
699
878
  # is configurable because to calculate the true socket peer address
700
879
  # a kernel syscall is required which for very fast rack handlers
701
880
  # slows down the handling significantly.
702
881
  #
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.
882
+ # There are 5 possible values:
883
+ #
884
+ # 1. **:socket** (the default) - read the peername from the socket using the
885
+ # syscall. This is the normal behavior.
886
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
887
+ # 3. **header: <http_header>**- set the remote address to the value of the
888
+ # provided http header. For instance:
889
+ # `set_remote_address header: "X-Real-IP"`.
890
+ # Only the first word (as separated by spaces or comma) is used, allowing
891
+ # headers such as X-Forwarded-For to be used as well.
892
+ # 4. **proxy_protocol: :v1**- set the remote address to the value read from the
893
+ # HAproxy PROXY protocol, version 1. If the request does not have the PROXY
894
+ # protocol attached to it, will fall back to :socket
895
+ # 5. **\<Any string\>** - this allows you to hardcode remote address to any value
896
+ # you wish. Because Puma never uses this field anyway, it's format is
897
+ # entirely in your hands.
898
+ #
717
899
  def set_remote_address(val=:socket)
718
900
  case val
719
901
  when :socket
@@ -728,6 +910,13 @@ module Puma
728
910
  if hdr = val[:header]
729
911
  @options[:remote_address] = :header
730
912
  @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
913
+ elsif protocol_version = val[:proxy_protocol]
914
+ @options[:remote_address] = :proxy_protocol
915
+ protocol_version = protocol_version.downcase.to_sym
916
+ unless [:v1].include?(protocol_version)
917
+ raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
918
+ end
919
+ @options[:remote_address_proxy_protocol] = protocol_version
731
920
  else
732
921
  raise "Invalid value for set_remote_address - #{val.inspect}"
733
922
  end
@@ -736,5 +925,88 @@ module Puma
736
925
  end
737
926
  end
738
927
 
928
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
929
+ # This option is similar to `preload_app` because the app is preloaded before forking,
930
+ # but it is compatible with phased restart.
931
+ #
932
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
933
+ # in a running app.
934
+ #
935
+ # A refork will automatically trigger once after the specified number of requests
936
+ # (default 1000), or pass 0 to disable auto refork.
937
+ #
938
+ # @note Cluster mode only.
939
+ # @version 5.0.0
940
+ #
941
+ def fork_worker(after_requests=1000)
942
+ @options[:fork_worker] = Integer(after_requests)
943
+ end
944
+
945
+ # When enabled, Puma will GC 4 times before forking workers.
946
+ # If available (Ruby 2.7+), we will also call GC.compact.
947
+ # Not recommended for non-MRI Rubies.
948
+ #
949
+ # Based on the work of Koichi Sasada and Aaron Patterson, this option may
950
+ # decrease memory utilization of preload-enabled cluster-mode Pumas. It will
951
+ # also increase time to boot and fork. See your logs for details on how much
952
+ # time this adds to your boot process. For most apps, it will be less than one
953
+ # second.
954
+ #
955
+ # @see Puma::Cluster#nakayoshi_gc
956
+ # @version 5.0.0
957
+ #
958
+ def nakayoshi_fork(enabled=true)
959
+ @options[:nakayoshi_fork] = enabled
960
+ end
961
+
962
+ # The number of requests to attempt inline before sending a client back to
963
+ # the reactor to be subject to normal ordering.
964
+ #
965
+ def max_fast_inline(num_of_requests)
966
+ @options[:max_fast_inline] = Float(num_of_requests)
967
+ end
968
+
969
+ # Specify the backend for the IO selector.
970
+ #
971
+ # Provided values will be passed directly to +NIO::Selector.new+, with the
972
+ # exception of +:auto+ which will let nio4r choose the backend.
973
+ #
974
+ # Check the documentation of +NIO::Selector.backends+ for the list of valid
975
+ # options. Note that the available options on your system will depend on the
976
+ # operating system. If you want to use the pure Ruby backend (not
977
+ # recommended due to its comparatively low performance), set environment
978
+ # variable +NIO4R_PURE+ to +true+.
979
+ #
980
+ # The default is +:auto+.
981
+ #
982
+ # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
983
+ #
984
+ def io_selector_backend(backend)
985
+ @options[:io_selector_backend] = backend.to_sym
986
+ end
987
+
988
+ def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
989
+ @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
990
+ end
991
+
992
+ private
993
+
994
+ # To avoid adding cert_pem and key_pem as URI params, we store them on the
995
+ # options[:store] from where Puma binder knows how to find and extract them.
996
+ def add_pem_values_to_options_store(opts)
997
+ return if defined?(JRUBY_VERSION)
998
+
999
+ @options[:store] ||= []
1000
+
1001
+ # Store cert_pem and key_pem to options[:store] if present
1002
+ [:cert, :key].each do |v|
1003
+ opt_key = :"#{v}_pem"
1004
+ if opts[opt_key]
1005
+ index = @options[:store].length
1006
+ @options[:store] << opts[opt_key]
1007
+ opts[v] = "store:#{index}"
1008
+ end
1009
+ end
1010
+ end
739
1011
  end
740
1012
  end