puma 3.11.4 → 6.0.1

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1717 -432
  3. data/LICENSE +23 -20
  4. data/README.md +190 -64
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +59 -21
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +69 -58
  9. data/docs/fork_worker.md +31 -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 +2 -2
  19. data/docs/plugins.md +22 -12
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +47 -22
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +95 -120
  25. data/docs/testing_benchmarks_local_files.md +150 -0
  26. data/docs/testing_test_rackup_ci_files.md +36 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +61 -3
  30. data/ext/puma_http11/http11_parser.c +106 -118
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +22 -38
  33. data/ext/puma_http11/http11_parser.rl +6 -4
  34. data/ext/puma_http11/http11_parser_common.rl +6 -6
  35. data/ext/puma_http11/mini_ssl.c +376 -93
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +250 -88
  40. data/ext/puma_http11/puma_http11.c +49 -57
  41. data/lib/puma/app/status.rb +71 -49
  42. data/lib/puma/binder.rb +243 -148
  43. data/lib/puma/cli.rb +50 -36
  44. data/lib/puma/client.rb +373 -233
  45. data/lib/puma/cluster/worker.rb +175 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +268 -235
  48. data/lib/puma/commonlogger.rb +4 -2
  49. data/lib/puma/configuration.rb +116 -88
  50. data/lib/puma/const.rb +49 -30
  51. data/lib/puma/control_cli.rb +123 -76
  52. data/lib/puma/detect.rb +33 -2
  53. data/lib/puma/dsl.rb +685 -135
  54. data/lib/puma/error_logger.rb +112 -0
  55. data/lib/puma/events.rb +17 -111
  56. data/lib/puma/io_buffer.rb +44 -5
  57. data/lib/puma/jruby_restart.rb +4 -59
  58. data/lib/puma/json_serialization.rb +96 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  60. data/lib/puma/launcher.rb +196 -130
  61. data/lib/puma/log_writer.rb +137 -0
  62. data/lib/puma/minissl/context_builder.rb +92 -0
  63. data/lib/puma/minissl.rb +249 -69
  64. data/lib/puma/null_io.rb +20 -1
  65. data/lib/puma/plugin/tmp_restart.rb +3 -1
  66. data/lib/puma/plugin.rb +9 -13
  67. data/lib/puma/rack/builder.rb +8 -9
  68. data/lib/puma/rack/urlmap.rb +2 -0
  69. data/lib/puma/rack_default.rb +3 -1
  70. data/lib/puma/reactor.rb +90 -187
  71. data/lib/puma/request.rb +644 -0
  72. data/lib/puma/runner.rb +94 -71
  73. data/lib/puma/server.rb +337 -715
  74. data/lib/puma/single.rb +27 -72
  75. data/lib/puma/state_file.rb +46 -7
  76. data/lib/puma/systemd.rb +47 -0
  77. data/lib/puma/thread_pool.rb +184 -93
  78. data/lib/puma/util.rb +23 -10
  79. data/lib/puma.rb +60 -3
  80. data/lib/rack/handler/puma.rb +17 -15
  81. data/tools/Dockerfile +16 -0
  82. data/tools/trickletest.rb +0 -1
  83. metadata +53 -33
  84. data/ext/puma_http11/io_buffer.c +0 -155
  85. data/lib/puma/accept_nonblock.rb +0 -23
  86. data/lib/puma/compat.rb +0 -14
  87. data/lib/puma/convenient.rb +0 -23
  88. data/lib/puma/daemon_ext.rb +0 -31
  89. data/lib/puma/delegation.rb +0 -11
  90. data/lib/puma/java_io_buffer.rb +0 -45
  91. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  92. data/lib/puma/tcp_logger.rb +0 -39
  93. data/tools/jungle/README.md +0 -19
  94. data/tools/jungle/init.d/README.md +0 -61
  95. data/tools/jungle/init.d/puma +0 -421
  96. data/tools/jungle/init.d/run-puma +0 -18
  97. data/tools/jungle/upstart/README.md +0 -61
  98. data/tools/jungle/upstart/puma-manager.conf +0 -31
  99. data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/dsl.rb CHANGED
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'const'
4
+ require_relative 'util'
5
+
1
6
  module Puma
2
- # The methods that are available for use inside the config file.
7
+ # The methods that are available for use inside the configuration file.
3
8
  # These same methods are used in Puma cli and the rack handler
4
9
  # internally.
5
10
  #
@@ -10,23 +15,108 @@ module Puma
10
15
  # end
11
16
  # config.load
12
17
  #
13
- # puts config.options[:binds]
14
- # "tcp://127.0.0.1:3001"
18
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3001"
15
19
  #
16
20
  # Used to load file:
17
21
  #
18
22
  # $ cat puma_config.rb
19
- # port 3002
23
+ # port 3002
24
+ #
25
+ # Resulting configuration:
20
26
  #
21
27
  # config = Configuration.new(config_file: "puma_config.rb")
22
28
  # config.load
23
29
  #
24
- # puts config.options[:binds]
25
- # # => "tcp://127.0.0.1:3002"
30
+ # puts config.options[:binds] # => "tcp://127.0.0.1:3002"
31
+ #
32
+ # You can also find many examples being used by the test suite in
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 |
26
50
  #
27
- # Detailed docs can be found in `examples/config.rb`
28
51
  class DSL
29
- 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
30
120
 
31
121
  def initialize(options, config)
32
122
  @config = config
@@ -55,6 +145,14 @@ module Puma
55
145
  @plugins.clear
56
146
  end
57
147
 
148
+ def set_default_host(host)
149
+ @options[:default_host] = host
150
+ end
151
+
152
+ def default_host
153
+ @options[:default_host] || Configuration::DEFAULTS[:tcp_host]
154
+ end
155
+
58
156
  def inject(&blk)
59
157
  instance_eval(&blk)
60
158
  end
@@ -69,8 +167,24 @@ module Puma
69
167
  @plugins << @config.load_plugin(name)
70
168
  end
71
169
 
72
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
73
- # be the app itself.
170
+ # Use an object or block as the rack application. This allows the
171
+ # configuration file to be the application itself.
172
+ #
173
+ # @example
174
+ # app do |env|
175
+ # body = 'Hello, World!'
176
+ #
177
+ # [
178
+ # 200,
179
+ # {
180
+ # 'Content-Type' => 'text/plain',
181
+ # 'Content-Length' => body.length.to_s
182
+ # },
183
+ # [body]
184
+ # ]
185
+ # end
186
+ #
187
+ # @see Puma::Configuration#app
74
188
  #
75
189
  def app(obj=nil, &block)
76
190
  obj ||= block
@@ -80,9 +194,20 @@ module Puma
80
194
  @options[:app] = obj
81
195
  end
82
196
 
83
- # Start the Puma control rack app on +url+. This app can be communicated
84
- # with to control the main server.
197
+ # Start the Puma control rack application on +url+. This application can
198
+ # be communicated with to control the main server. Additionally, you can
199
+ # provide an authentication token, so all requests to the control server
200
+ # will need to include that token as a query parameter. This allows for
201
+ # simple authentication.
202
+ #
203
+ # Check out {Puma::App::Status} to see what the app has available.
85
204
  #
205
+ # @example
206
+ # activate_control_app 'unix:///var/run/pumactl.sock'
207
+ # @example
208
+ # activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
209
+ # @example
210
+ # activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
86
211
  def activate_control_app(url="auto", opts={})
87
212
  if url == "auto"
88
213
  path = Configuration.temp_path
@@ -93,7 +218,12 @@ module Puma
93
218
  end
94
219
 
95
220
  if opts[:no_token]
96
- auth_token = :none
221
+ # We need to use 'none' rather than :none because this value will be
222
+ # passed on to an instance of OptionParser, which doesn't support
223
+ # symbols as option values.
224
+ #
225
+ # See: https://github.com/puma/puma/issues/1193#issuecomment-305995488
226
+ auth_token = 'none'
97
227
  else
98
228
  auth_token = opts[:auth_token]
99
229
  auth_token ||= Configuration.random_token
@@ -110,22 +240,35 @@ module Puma
110
240
  @options[:config_files] << file
111
241
  end
112
242
 
113
- # Adds a binding for the server to +url+. tcp://, unix://, and ssl:// are the only accepted
114
- # protocols. Use query parameters within the url to specify options.
243
+ # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
244
+ # accepted protocols. Multiple urls can be bound to, calling +bind+ does
245
+ # not overwrite previous bindings.
115
246
  #
116
- # @note multiple urls can be bound to, calling `bind` does not overwrite previous bindings.
247
+ # The default is "tcp://0.0.0.0:9292".
117
248
  #
118
- # @example Explicitly the socket backlog depth (default is 1024)
119
- # bind('unix:///var/run/puma.sock?backlog=2048')
249
+ # You can use query parameters within the url to specify options:
120
250
  #
121
- # @example Set up ssl cert
122
- # bind('ssl://127.0.0.1:9292?key=key.key&cert=cert.pem')
251
+ # * Set the socket backlog depth with +backlog+, default is 1024.
252
+ # * Set up an SSL certificate with +key+ & +cert+.
253
+ # * Set up an SSL certificate for mTLS with +key+, +cert+, +ca+ and +verify_mode+.
254
+ # * Set whether to optimize for low latency instead of throughput with
255
+ # +low_latency+, default is to not optimize for low latency. This is done
256
+ # via +Socket::TCP_NODELAY+.
257
+ # * Set socket permissions with +umask+.
123
258
  #
124
- # @example Prefer low-latency over higher throughput (via `Socket::TCP_NODELAY`)
125
- # bind('tcp://0.0.0.0:9292?low_latency=true')
259
+ # @example Backlog depth
260
+ # bind 'unix:///var/run/puma.sock?backlog=512'
261
+ # @example SSL cert
262
+ # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
263
+ # @example SSL cert for mutual TLS (mTLS)
264
+ # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem&ca=ca.pem&verify_mode=force_peer'
265
+ # @example Disable optimization for low latency
266
+ # bind 'tcp://0.0.0.0:9292?low_latency=false'
267
+ # @example Socket permissions
268
+ # bind 'unix:///var/run/puma.sock?umask=0111'
269
+ # @see Puma::Runner#load_and_bind
270
+ # @see Puma::Cluster#run
126
271
  #
127
- # @example Set socket permissions
128
- # bind('unix:///var/run/puma.sock?umask=0111')
129
272
  def bind(url)
130
273
  @options[:binds] ||= []
131
274
  @options[:binds] << url
@@ -135,48 +278,75 @@ module Puma
135
278
  @options[:binds] = []
136
279
  end
137
280
 
281
+ # Bind to (systemd) activated sockets, regardless of configured binds.
282
+ #
283
+ # Systemd can present sockets as file descriptors that are already opened.
284
+ # By default Puma will use these but only if it was explicitly told to bind
285
+ # to the socket. If not, it will close the activated sockets. This means
286
+ # all configuration is duplicated.
287
+ #
288
+ # Binds can contain additional configuration, but only SSL config is really
289
+ # relevant since the unix and TCP socket options are ignored.
290
+ #
291
+ # This means there is a lot of duplicated configuration for no additional
292
+ # value in most setups. This method tells the launcher to bind to all
293
+ # activated sockets, regardless of existing bind.
294
+ #
295
+ # To clear configured binds, the value only can be passed. This will clear
296
+ # out any binds that may have been configured.
297
+ #
298
+ # @example Use any systemd activated sockets as well as configured binds
299
+ # bind_to_activated_sockets
300
+ #
301
+ # @example Only bind to systemd activated sockets, ignoring other binds
302
+ # bind_to_activated_sockets 'only'
303
+ def bind_to_activated_sockets(bind=true)
304
+ @options[:bind_to_activated_sockets] = bind
305
+ end
306
+
138
307
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
139
308
  #
309
+ # @example
310
+ # port 9292
140
311
  def port(port, host=nil)
141
- host ||= Configuration::DefaultTCPHost
142
- bind "tcp://#{host}:#{port}"
312
+ host ||= default_host
313
+ bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
143
314
  end
144
315
 
145
- # Define how long persistent connections can be idle before puma closes
146
- # them
147
- #
316
+ # Define how long persistent connections can be idle before Puma closes them.
317
+ # @see Puma::Server.new
148
318
  def persistent_timeout(seconds)
149
319
  @options[:persistent_timeout] = Integer(seconds)
150
320
  end
151
321
 
152
- # Define how long the tcp socket stays open, if no data has been received
153
- #
322
+ # Define how long the tcp socket stays open, if no data has been received.
323
+ # @see Puma::Server.new
154
324
  def first_data_timeout(seconds)
155
325
  @options[:first_data_timeout] = Integer(seconds)
156
326
  end
157
327
 
158
328
  # Work around leaky apps that leave garbage in Thread locals
159
- # across requests
160
- #
329
+ # across requests.
161
330
  def clean_thread_locals(which=true)
162
331
  @options[:clean_thread_locals] = which
163
332
  end
164
333
 
165
- # Daemonize the server into the background. Highly suggest that
166
- # this be combined with +pidfile+ and +stdout_redirect+.
167
- def daemonize(which=true)
168
- @options[:daemon] = which
169
- end
170
-
171
- # When shutting down, drain the accept socket of pending
172
- # connections and process them. This loops over the accept
173
- # socket until there are no more read events and then stops
174
- # looking and waits for the requests to finish.
334
+ # When shutting down, drain the accept socket of pending connections and
335
+ # process them. This loops over the accept socket until there are no more
336
+ # read events and then stops looking and waits for the requests to finish.
337
+ # @see Puma::Server#graceful_shutdown
338
+ #
175
339
  def drain_on_shutdown(which=true)
176
340
  @options[:drain_on_shutdown] = which
177
341
  end
178
342
 
179
- # Set the environment in which the Rack's app will run.
343
+ # Set the environment in which the rack's app will run. The value must be
344
+ # a string.
345
+ #
346
+ # The default is "development".
347
+ #
348
+ # @example
349
+ # environment 'production'
180
350
  def environment(environment)
181
351
  @options[:environment] = environment
182
352
  end
@@ -188,6 +358,7 @@ module Puma
188
358
  #
189
359
  # Puma always waits a few seconds after killing a thread for it to try
190
360
  # to finish up it's work, even in :immediately mode.
361
+ # @see Puma::Server#graceful_shutdown
191
362
  def force_shutdown_after(val=:forever)
192
363
  i = case val
193
364
  when :forever
@@ -195,37 +366,48 @@ module Puma
195
366
  when :immediately
196
367
  0
197
368
  else
198
- Integer(val)
369
+ Float(val)
199
370
  end
200
371
 
201
372
  @options[:force_shutdown_after] = i
202
373
  end
203
374
 
204
375
  # Code to run before doing a restart. This code should
205
- # close logfiles, database connections, etc.
376
+ # close log files, database connections, etc.
206
377
  #
207
378
  # This can be called multiple times to add code each time.
208
379
  #
380
+ # @example
381
+ # on_restart do
382
+ # puts 'On restart...'
383
+ # end
209
384
  def on_restart(&block)
210
385
  @options[:on_restart] ||= []
211
386
  @options[:on_restart] << block
212
387
  end
213
388
 
214
- # Command to use to restart puma. This should be just how to
215
- # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
216
- # to puma, as those are the same as the original process.
389
+ # Command to use to restart Puma. This should be just how to
390
+ # load Puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
391
+ # to Puma, as those are the same as the original process.
217
392
  #
393
+ # @example
394
+ # restart_command '/u/app/lolcat/bin/restart_puma'
218
395
  def restart_command(cmd)
219
396
  @options[:restart_cmd] = cmd.to_s
220
397
  end
221
398
 
222
- # Store the pid of the server in the file at +path+.
399
+ # Store the pid of the server in the file at "path".
400
+ #
401
+ # @example
402
+ # pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
223
403
  def pidfile(path)
224
404
  @options[:pidfile] = path.to_s
225
405
  end
226
406
 
227
- # Disable request logging.
407
+ # Disable request logging, if this isn't used it'll be enabled by default.
228
408
  #
409
+ # @example
410
+ # quiet
229
411
  def quiet(which=true)
230
412
  @options[:log_requests] = !which
231
413
  end
@@ -244,30 +426,54 @@ module Puma
244
426
 
245
427
  # Load +path+ as a rackup file.
246
428
  #
429
+ # The default is "config.ru".
430
+ #
431
+ # @example
432
+ # rackup '/u/apps/lolcat/config.ru'
247
433
  def rackup(path)
248
- @options[:rackup] = path.to_s
434
+ @options[:rackup] ||= path.to_s
249
435
  end
250
436
 
251
- # Run Puma in TCP mode
252
- #
253
- def tcp_mode!
254
- @options[:mode] = :tcp
437
+ # Allows setting `env['rack.url_scheme']`.
438
+ # Only necessary if X-Forwarded-Proto is not being set by your proxy
439
+ # Normal values are 'http' or 'https'.
440
+ def rack_url_scheme(scheme=nil)
441
+ @options[:rack_url_scheme] = scheme
255
442
  end
256
443
 
257
444
  def early_hints(answer=true)
258
445
  @options[:early_hints] = answer
259
446
  end
260
447
 
261
- # Redirect STDOUT and STDERR to files specified.
448
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
449
+ # specifies whether the output is appended, the default is +false+.
450
+ #
451
+ # @example
452
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr'
453
+ # @example
454
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr', true
262
455
  def stdout_redirect(stdout=nil, stderr=nil, append=false)
263
456
  @options[:redirect_stdout] = stdout
264
457
  @options[:redirect_stderr] = stderr
265
458
  @options[:redirect_append] = append
266
459
  end
267
460
 
461
+ def log_formatter(&block)
462
+ @options[:log_formatter] = block
463
+ end
464
+
268
465
  # Configure +min+ to be the minimum number of threads to use to answer
269
466
  # requests and +max+ the maximum.
270
467
  #
468
+ # The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
469
+ # (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
470
+ #
471
+ # If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
472
+ #
473
+ # @example
474
+ # threads 0, 16
475
+ # @example
476
+ # threads 5, 5
271
477
  def threads(min, max)
272
478
  min = Integer(min)
273
479
  max = Integer(max)
@@ -283,115 +489,242 @@ module Puma
283
489
  @options[:max_threads] = max
284
490
  end
285
491
 
286
- def ssl_bind(host, port, opts)
287
- verify = opts.fetch(:verify_mode, 'none')
288
-
289
- if defined?(JRUBY_VERSION)
290
- keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
291
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}"
292
- else
293
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&verify_mode=#{verify}"
294
- end
492
+ # Instead of using +bind+ and manually constructing a URI like:
493
+ #
494
+ # bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
495
+ #
496
+ # you can use the this method.
497
+ #
498
+ # When binding on localhost you don't need to specify +cert+ and +key+,
499
+ # Puma will assume you are using the +localhost+ gem and try to load the
500
+ # appropriate files.
501
+ #
502
+ # When using the options hash parameter, the `reuse:` value is either
503
+ # `true`, which sets reuse 'on' with default values, or a hash, with `:size`
504
+ # and/or `:timeout` keys, each with integer values.
505
+ #
506
+ # @example
507
+ # ssl_bind '127.0.0.1', '9292', {
508
+ # cert: path_to_cert,
509
+ # key: path_to_key,
510
+ # ssl_cipher_filter: cipher_filter, # optional
511
+ # verify_mode: verify_mode, # default 'none'
512
+ # verification_flags: flags, # optional, not supported by JRuby
513
+ # reuse: true # optional
514
+ # }
515
+ #
516
+ # @example Using self-signed certificate with the +localhost+ gem:
517
+ # ssl_bind '127.0.0.1', '9292'
518
+ #
519
+ # @example Alternatively, you can provide +cert_pem+ and +key_pem+:
520
+ # ssl_bind '127.0.0.1', '9292', {
521
+ # cert_pem: File.read(path_to_cert),
522
+ # key_pem: File.read(path_to_key),
523
+ # reuse: {size: 2_000, timeout: 20} # optional
524
+ # }
525
+ #
526
+ # @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
527
+ # ssl_bind '127.0.0.1', '9292', {
528
+ # keystore: path_to_keystore,
529
+ # keystore_pass: password,
530
+ # ssl_cipher_list: cipher_list, # optional
531
+ # verify_mode: verify_mode # default 'none'
532
+ # }
533
+ def ssl_bind(host, port, opts = {})
534
+ add_pem_values_to_options_store(opts)
535
+ bind self.class.ssl_bind_str(host, port, opts)
295
536
  end
296
537
 
297
538
  # Use +path+ as the file to store the server info state. This is
298
- # used by pumactl to query and control the server.
539
+ # used by +pumactl+ to query and control the server.
299
540
  #
541
+ # @example
542
+ # state_path '/u/apps/lolcat/tmp/pids/puma.state'
300
543
  def state_path(path)
301
544
  @options[:state] = path.to_s
302
545
  end
303
546
 
304
- # *Cluster mode only* How many worker processes to run.
547
+ # Use +permission+ to restrict permissions for the state file.
548
+ #
549
+ # @example
550
+ # state_permission 0600
551
+ # @version 5.0.0
552
+ #
553
+ def state_permission(permission)
554
+ @options[:state_permission] = permission
555
+ end
556
+
557
+ # How many worker processes to run. Typically this is set to
558
+ # the number of available cores.
305
559
  #
560
+ # The default is the value of the environment variable +WEB_CONCURRENCY+ if
561
+ # set, otherwise 0.
562
+ #
563
+ # @note Cluster mode only.
564
+ # @see Puma::Cluster
306
565
  def workers(count)
307
566
  @options[:workers] = count.to_i
308
567
  end
309
568
 
310
- # *Cluster mode only* Code to run immediately before master process
569
+ # Disable warning message when running in cluster mode with a single worker.
570
+ #
571
+ # Cluster mode has some overhead of running an additional 'control' process
572
+ # in order to manage the cluster. If only running a single worker it is
573
+ # likely not worth paying that overhead vs running in single mode with
574
+ # additional threads instead.
575
+ #
576
+ # There are some scenarios where running cluster mode with a single worker
577
+ # may still be warranted and valid under certain deployment scenarios, see
578
+ # https://github.com/puma/puma/issues/2534
579
+ #
580
+ # Moving from workers = 1 to workers = 0 will save 10-30% of memory use.
581
+ #
582
+ # @note Cluster mode only.
583
+ def silence_single_worker_warning
584
+ @options[:silence_single_worker_warning] = true
585
+ end
586
+
587
+ # Code to run immediately before master process
311
588
  # forks workers (once on boot). These hooks can block if necessary
312
- # to wait for background operations unknown to puma to finish before
589
+ # to wait for background operations unknown to Puma to finish before
313
590
  # the process terminates.
314
- # This can be used to close any connections to remote servers (database, redis, ...)
315
- # that were opened when preloading the code
591
+ # This can be used to close any connections to remote servers (database,
592
+ # Redis, ...) that were opened when preloading the code.
316
593
  #
317
- # This can be called multiple times to add hooks.
594
+ # This can be called multiple times to add several hooks.
318
595
  #
596
+ # @note Cluster mode only.
597
+ # @example
598
+ # before_fork do
599
+ # puts "Starting workers..."
600
+ # end
319
601
  def before_fork(&block)
320
602
  @options[:before_fork] ||= []
321
603
  @options[:before_fork] << block
322
604
  end
323
605
 
324
- # *Cluster mode only* Code to run in a worker when it boots to setup
606
+ # Code to run in a worker when it boots to setup
325
607
  # the process before booting the app.
326
608
  #
327
- # This can be called multiple times to add hooks.
609
+ # This can be called multiple times to add several hooks.
328
610
  #
329
- def on_worker_boot(&block)
330
- @options[:before_worker_boot] ||= []
331
- @options[:before_worker_boot] << block
611
+ # @note Cluster mode only.
612
+ # @example
613
+ # on_worker_boot do
614
+ # puts 'Before worker boot...'
615
+ # end
616
+ def on_worker_boot(key = nil, &block)
617
+ process_hook :before_worker_boot, key, block, 'on_worker_boot'
332
618
  end
333
619
 
334
- # *Cluster mode only* Code to run immediately before a worker shuts
620
+ # Code to run immediately before a worker shuts
335
621
  # down (after it has finished processing HTTP requests). These hooks
336
622
  # can block if necessary to wait for background operations unknown
337
- # to puma to finish before the process terminates.
623
+ # to Puma to finish before the process terminates.
338
624
  #
339
- # This can be called multiple times to add hooks.
625
+ # This can be called multiple times to add several hooks.
340
626
  #
341
- def on_worker_shutdown(&block)
342
- @options[:before_worker_shutdown] ||= []
343
- @options[:before_worker_shutdown] << block
627
+ # @note Cluster mode only.
628
+ # @example
629
+ # on_worker_shutdown do
630
+ # puts 'On worker shutdown...'
631
+ # end
632
+ def on_worker_shutdown(key = nil, &block)
633
+ process_hook :before_worker_shutdown, key, block, 'on_worker_shutdown'
344
634
  end
345
635
 
346
- # *Cluster mode only* Code to run in the master when it is
347
- # about to create the worker by forking itself.
636
+ # Code to run in the master right before a worker is started. The worker's
637
+ # index is passed as an argument.
348
638
  #
349
- # This can be called multiple times to add hooks.
639
+ # This can be called multiple times to add several hooks.
350
640
  #
641
+ # @note Cluster mode only.
642
+ # @example
643
+ # on_worker_fork do
644
+ # puts 'Before worker fork...'
645
+ # end
351
646
  def on_worker_fork(&block)
352
- @options[:before_worker_fork] ||= []
353
- @options[:before_worker_fork] << block
647
+ process_hook :before_worker_fork, nil, block, 'on_worker_fork'
354
648
  end
355
649
 
356
- # *Cluster mode only* Code to run in the master after it starts
357
- # a worker.
650
+ # Code to run in the master after a worker has been started. The worker's
651
+ # index is passed as an argument.
358
652
  #
359
- # This can be called multiple times to add hooks.
653
+ # This is called everytime a worker is to be started.
360
654
  #
655
+ # @note Cluster mode only.
656
+ # @example
657
+ # after_worker_fork do
658
+ # puts 'After worker fork...'
659
+ # end
361
660
  def after_worker_fork(&block)
362
- @options[:after_worker_fork] ||= []
363
- @options[:after_worker_fork] = block
661
+ process_hook :after_worker_fork, nil, block, 'after_worker_fork'
364
662
  end
365
663
 
366
664
  alias_method :after_worker_boot, :after_worker_fork
367
665
 
368
- # The directory to operate out of.
369
- def directory(dir)
370
- @options[:directory] = dir.to_s
666
+ # When `fork_worker` is enabled, code to run in Worker 0
667
+ # before all other workers are re-forked from this process,
668
+ # after the server has temporarily stopped serving requests
669
+ # (once per complete refork cycle).
670
+ #
671
+ # This can be used to trigger extra garbage-collection to maximize
672
+ # copy-on-write efficiency, or close any connections to remote servers
673
+ # (database, Redis, ...) that were opened while the server was running.
674
+ #
675
+ # This can be called multiple times to add several hooks.
676
+ #
677
+ # @note Cluster mode with `fork_worker` enabled only.
678
+ # @example
679
+ # on_refork do
680
+ # 3.times {GC.start}
681
+ # end
682
+ # @version 5.0.0
683
+ #
684
+ def on_refork(key = nil, &block)
685
+ process_hook :before_refork, key, block, 'on_refork'
371
686
  end
372
687
 
373
- # DEPRECATED: The directory to operate out of.
374
- def worker_directory(dir)
375
- $stderr.puts "worker_directory is deprecated. Please use `directory`"
376
- directory dir
688
+ # Code to run out-of-band when the worker is idle.
689
+ # These hooks run immediately after a request has finished
690
+ # processing and there are no busy threads on the worker.
691
+ # The worker doesn't accept new requests until this code finishes.
692
+ #
693
+ # This hook is useful for running out-of-band garbage collection
694
+ # or scheduling asynchronous tasks to execute after a response.
695
+ #
696
+ # This can be called multiple times to add several hooks.
697
+ def out_of_band(&block)
698
+ process_hook :out_of_band, nil, block, 'out_of_band'
377
699
  end
378
700
 
379
- # Run the app as a raw TCP app instead of an HTTP rack app
380
- def tcp_mode
381
- @options[:mode] = :tcp
701
+ # The directory to operate out of.
702
+ #
703
+ # The default is the current directory.
704
+ #
705
+ # @example
706
+ # directory '/u/apps/lolcat'
707
+ def directory(dir)
708
+ @options[:directory] = dir.to_s
382
709
  end
383
710
 
384
- # *Cluster mode only* Preload the application before starting
385
- # the workers and setting up the listen ports. This conflicts
386
- # with using the phased restart feature, you can't use both.
711
+ # Preload the application before starting the workers; this conflicts with
712
+ # phased restart feature. On by default if your app uses more than 1 worker.
387
713
  #
714
+ # @note Cluster mode only.
715
+ # @example
716
+ # preload_app!
388
717
  def preload_app!(answer=true)
389
718
  @options[:preload_app] = answer
390
719
  end
391
720
 
392
- # Use +obj+ or +block+ as the low level error handler. This allows a config file to
393
- # change the default error on the server.
721
+ # Use +obj+ or +block+ as the low level error handler. This allows the
722
+ # configuration file to change the default error on the server.
394
723
  #
724
+ # @example
725
+ # lowlevel_error_handler do |err|
726
+ # [200, {}, ["error page"]]
727
+ # end
395
728
  def lowlevel_error_handler(obj=nil, &block)
396
729
  obj ||= block
397
730
  raise "Provide either a #call'able or a block" unless obj
@@ -401,42 +734,153 @@ module Puma
401
734
  # This option is used to allow your app and its gems to be
402
735
  # properly reloaded when not using preload.
403
736
  #
404
- # When set, if puma detects that it's been invoked in the
737
+ # When set, if Puma detects that it's been invoked in the
405
738
  # context of Bundler, it will cleanup the environment and
406
739
  # re-run itself outside the Bundler environment, but directly
407
740
  # using the files that Bundler has setup.
408
741
  #
409
- # This means that puma is now decoupled from your Bundler
742
+ # This means that Puma is now decoupled from your Bundler
410
743
  # context and when each worker loads, it will be loading a
411
744
  # new Bundler context and thus can float around as the release
412
745
  # dictates.
746
+ #
747
+ # @see extra_runtime_dependencies
748
+ #
749
+ # @note This is incompatible with +preload_app!+.
750
+ # @note This is only supported for RubyGems 2.2+
413
751
  def prune_bundler(answer=true)
414
752
  @options[:prune_bundler] = answer
415
753
  end
416
754
 
417
- # Additional text to display in process listing
755
+ # By default, Puma will raise SignalException when SIGTERM is received. In
756
+ # environments where SIGTERM is something expected, you can suppress these
757
+ # with this option.
758
+ #
759
+ # This can be useful for example in Kubernetes, where rolling restart is
760
+ # guaranteed usually on infrastructure level.
761
+ #
762
+ # @example
763
+ # raise_exception_on_sigterm false
764
+ # @see Puma::Launcher#setup_signals
765
+ # @see Puma::Cluster#setup_signals
766
+ #
767
+ def raise_exception_on_sigterm(answer=true)
768
+ @options[:raise_exception_on_sigterm] = answer
769
+ end
770
+
771
+ # When using prune_bundler, if extra runtime dependencies need to be loaded to
772
+ # initialize your app, then this setting can be used. This includes any Puma plugins.
773
+ #
774
+ # Before bundler is pruned, the gem names supplied will be looked up in the bundler
775
+ # context and then loaded again after bundler is pruned.
776
+ # Only applies if prune_bundler is used.
777
+ #
778
+ # @example
779
+ # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
780
+ # @example
781
+ # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
782
+ # @see Puma::Launcher#extra_runtime_deps_directories
783
+ #
784
+ def extra_runtime_dependencies(answer = [])
785
+ @options[:extra_runtime_dependencies] = Array(answer)
786
+ end
787
+
788
+ # Additional text to display in process listing.
789
+ #
790
+ # If you do not specify a tag, Puma will infer it. If you do not want Puma
791
+ # to add a tag, use an empty string.
792
+ #
793
+ # @example
794
+ # tag 'app name'
795
+ # @example
796
+ # tag ''
418
797
  def tag(string)
419
798
  @options[:tag] = string.to_s
420
799
  end
421
800
 
422
- # *Cluster mode only* Set the timeout for workers in seconds
423
- # When set the master process will terminate any workers
424
- # that have not checked in within the given +timeout+.
425
- # This mitigates hung processes. Default value is 60 seconds.
801
+ # Change the default interval for checking workers.
802
+ #
803
+ # The default value is 5 seconds.
804
+ #
805
+ # @note Cluster mode only.
806
+ # @example
807
+ # worker_check_interval 5
808
+ # @see Puma::Cluster#check_workers
809
+ #
810
+ def worker_check_interval(interval)
811
+ @options[:worker_check_interval] = Integer(interval)
812
+ end
813
+
814
+ # Verifies that all workers have checked in to the master process within
815
+ # the given timeout. If not the worker process will be restarted. This is
816
+ # not a request timeout, it is to protect against a hung or dead process.
817
+ # Setting this value will not protect against slow requests.
818
+ #
819
+ # The minimum value is 6 seconds, the default value is 60 seconds.
820
+ #
821
+ # @note Cluster mode only.
822
+ # @example
823
+ # worker_timeout 60
824
+ # @see Puma::Cluster::Worker#ping_timeout
825
+ #
426
826
  def worker_timeout(timeout)
427
- @options[:worker_timeout] = Integer(timeout)
827
+ timeout = Integer(timeout)
828
+ min = @options.fetch(:worker_check_interval, Configuration::DEFAULTS[:worker_check_interval])
829
+
830
+ if timeout <= min
831
+ raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
832
+ end
833
+
834
+ @options[:worker_timeout] = timeout
428
835
  end
429
836
 
430
- # *Cluster mode only* Set the timeout for workers to boot
837
+ # Change the default worker timeout for booting.
838
+ #
839
+ # If unspecified, this defaults to the value of worker_timeout.
840
+ #
841
+ # @note Cluster mode only.
842
+ #
843
+ # @example
844
+ # worker_boot_timeout 60
845
+ # @see Puma::Cluster::Worker#ping_timeout
846
+ #
431
847
  def worker_boot_timeout(timeout)
432
848
  @options[:worker_boot_timeout] = Integer(timeout)
433
849
  end
434
850
 
435
- # *Cluster mode only* Set the timeout for worker shutdown
851
+ # Set the timeout for worker shutdown.
852
+ #
853
+ # @note Cluster mode only.
854
+ # @see Puma::Cluster::Worker#term
855
+ #
436
856
  def worker_shutdown_timeout(timeout)
437
857
  @options[:worker_shutdown_timeout] = Integer(timeout)
438
858
  end
439
859
 
860
+ # Set the strategy for worker culling.
861
+ #
862
+ # There are two possible values:
863
+ #
864
+ # 1. **:youngest** - the youngest workers (i.e. the workers that were
865
+ # the most recently started) will be culled.
866
+ # 2. **:oldest** - the oldest workers (i.e. the workers that were started
867
+ # the longest time ago) will be culled.
868
+ #
869
+ # @note Cluster mode only.
870
+ # @example
871
+ # worker_culling_strategy :oldest
872
+ # @see Puma::Cluster#cull_workers
873
+ #
874
+ def worker_culling_strategy(strategy)
875
+ stategy = strategy.to_sym
876
+
877
+ if ![:youngest, :oldest].include?(strategy)
878
+ raise "Invalid value for worker_culling_strategy - #{stategy}"
879
+ end
880
+
881
+ @options[:worker_culling_strategy] = strategy
882
+ end
883
+
440
884
  # When set to true (the default), workers accept all requests
441
885
  # and queue them before passing them to the handlers.
442
886
  # When set to false, each worker process accepts exactly as
@@ -449,7 +893,8 @@ module Puma
449
893
  # Note that setting this to false disables HTTP keepalive and
450
894
  # slow clients will occupy a handler thread while the request
451
895
  # is being sent. A reverse proxy, such as nginx, can handle
452
- # slow clients and queue requests before they reach puma.
896
+ # slow clients and queue requests before they reach Puma.
897
+ # @see Puma::Server
453
898
  def queue_requests(answer=true)
454
899
  @options[:queue_requests] = answer
455
900
  end
@@ -457,29 +902,50 @@ module Puma
457
902
  # When a shutdown is requested, the backtraces of all the
458
903
  # threads will be written to $stdout. This can help figure
459
904
  # out why shutdown is hanging.
905
+ #
460
906
  def shutdown_debug(val=true)
461
907
  @options[:shutdown_debug] = val
462
908
  end
463
909
 
910
+
911
+ # Attempts to route traffic to less-busy workers by causing them to delay
912
+ # listening on the socket, allowing workers which are not processing any
913
+ # requests to pick up new requests first.
914
+ #
915
+ # Only works on MRI. For all other interpreters, this setting does nothing.
916
+ # @see Puma::Server#handle_servers
917
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
918
+ # @version 5.0.0
919
+ #
920
+ def wait_for_less_busy_worker(val=0.005)
921
+ @options[:wait_for_less_busy_worker] = val.to_f
922
+ end
923
+
464
924
  # Control how the remote address of the connection is set. This
465
925
  # is configurable because to calculate the true socket peer address
466
926
  # a kernel syscall is required which for very fast rack handlers
467
927
  # slows down the handling significantly.
468
928
  #
469
- # There are 4 possible values:
470
- #
471
- # * :socket (the default) - read the peername from the socket using the
472
- # syscall. This is the normal behavior.
473
- # * :localhost - set the remote address to "127.0.0.1"
474
- # * header: http_header - set the remote address to the value of the
475
- # provided http header. For instance:
476
- # `set_remote_address header: "X-Real-IP"`.
477
- # Only the first word (as separated by spaces or comma)
478
- # is used, allowing headers such as X-Forwarded-For
479
- # to be used as well.
480
- # * Any string - this allows you to hardcode remote address to any value
481
- # you wish. Because puma never uses this field anyway, it's
482
- # format is entirely in your hands.
929
+ # There are 5 possible values:
930
+ #
931
+ # 1. **:socket** (the default) - read the peername from the socket using the
932
+ # syscall. This is the normal behavior. If this fails for any reason (e.g.,
933
+ # if the peer disconnects between the connection being accepted and the getpeername
934
+ # system call), Puma will return "0.0.0.0"
935
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
936
+ # 3. **header: <http_header>**- set the remote address to the value of the
937
+ # provided http header. For instance:
938
+ # `set_remote_address header: "X-Real-IP"`.
939
+ # Only the first word (as separated by spaces or comma) is used, allowing
940
+ # headers such as X-Forwarded-For to be used as well. If this header is absent,
941
+ # Puma will fall back to the behavior of :socket
942
+ # 4. **proxy_protocol: :v1**- set the remote address to the value read from the
943
+ # HAproxy PROXY protocol, version 1. If the request does not have the PROXY
944
+ # protocol attached to it, will fall back to :socket
945
+ # 5. **\<Any string\>** - this allows you to hardcode remote address to any value
946
+ # you wish. Because Puma never uses this field anyway, it's format is
947
+ # entirely in your hands.
948
+ #
483
949
  def set_remote_address(val=:socket)
484
950
  case val
485
951
  when :socket
@@ -493,7 +959,14 @@ module Puma
493
959
  when Hash
494
960
  if hdr = val[:header]
495
961
  @options[:remote_address] = :header
496
- @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
962
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
963
+ elsif protocol_version = val[:proxy_protocol]
964
+ @options[:remote_address] = :proxy_protocol
965
+ protocol_version = protocol_version.downcase.to_sym
966
+ unless [:v1].include?(protocol_version)
967
+ raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
968
+ end
969
+ @options[:remote_address_proxy_protocol] = protocol_version
497
970
  else
498
971
  raise "Invalid value for set_remote_address - #{val.inspect}"
499
972
  end
@@ -502,5 +975,82 @@ module Puma
502
975
  end
503
976
  end
504
977
 
978
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
979
+ # This option is similar to `preload_app` because the app is preloaded before forking,
980
+ # but it is compatible with phased restart.
981
+ #
982
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
983
+ # in a running app.
984
+ #
985
+ # A refork will automatically trigger once after the specified number of requests
986
+ # (default 1000), or pass 0 to disable auto refork.
987
+ #
988
+ # @note Cluster mode only.
989
+ # @version 5.0.0
990
+ #
991
+ def fork_worker(after_requests=1000)
992
+ @options[:fork_worker] = Integer(after_requests)
993
+ end
994
+
995
+ # The number of requests to attempt inline before sending a client back to
996
+ # the reactor to be subject to normal ordering.
997
+ #
998
+ def max_fast_inline(num_of_requests)
999
+ @options[:max_fast_inline] = Float(num_of_requests)
1000
+ end
1001
+
1002
+ # Specify the backend for the IO selector.
1003
+ #
1004
+ # Provided values will be passed directly to +NIO::Selector.new+, with the
1005
+ # exception of +:auto+ which will let nio4r choose the backend.
1006
+ #
1007
+ # Check the documentation of +NIO::Selector.backends+ for the list of valid
1008
+ # options. Note that the available options on your system will depend on the
1009
+ # operating system. If you want to use the pure Ruby backend (not
1010
+ # recommended due to its comparatively low performance), set environment
1011
+ # variable +NIO4R_PURE+ to +true+.
1012
+ #
1013
+ # The default is +:auto+.
1014
+ #
1015
+ # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
1016
+ #
1017
+ def io_selector_backend(backend)
1018
+ @options[:io_selector_backend] = backend.to_sym
1019
+ end
1020
+
1021
+ def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
1022
+ @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
1023
+ end
1024
+
1025
+ private
1026
+
1027
+ # To avoid adding cert_pem and key_pem as URI params, we store them on the
1028
+ # options[:store] from where Puma binder knows how to find and extract them.
1029
+ def add_pem_values_to_options_store(opts)
1030
+ return if defined?(JRUBY_VERSION)
1031
+
1032
+ @options[:store] ||= []
1033
+
1034
+ # Store cert_pem and key_pem to options[:store] if present
1035
+ [:cert, :key].each do |v|
1036
+ opt_key = :"#{v}_pem"
1037
+ if opts[opt_key]
1038
+ index = @options[:store].length
1039
+ @options[:store] << opts[opt_key]
1040
+ opts[v] = "store:#{index}"
1041
+ end
1042
+ end
1043
+ end
1044
+
1045
+ def process_hook(options_key, key, block, meth)
1046
+ @options[options_key] ||= []
1047
+ if ON_WORKER_KEY.include? key.class
1048
+ @options[options_key] << [block, key.to_sym]
1049
+ elsif key.nil?
1050
+ @options[options_key] << block
1051
+ else
1052
+ raise "'#{method}' key must be String or Symbol"
1053
+ end
1054
+ end
505
1055
  end
506
1056
  end