puma 4.3.12 → 5.6.4

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