puma 3.0.0.rc1 → 5.0.0.beta1

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 (91) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +703 -70
  3. data/LICENSE +23 -20
  4. data/README.md +173 -163
  5. data/docs/architecture.md +37 -0
  6. data/{DEPLOYMENT.md → docs/deployment.md} +28 -6
  7. data/docs/fork_worker.md +31 -0
  8. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  9. data/docs/images/puma-connection-flow.png +0 -0
  10. data/docs/images/puma-general-arch.png +0 -0
  11. data/docs/jungle/README.md +13 -0
  12. data/docs/jungle/rc.d/README.md +74 -0
  13. data/docs/jungle/rc.d/puma +61 -0
  14. data/docs/jungle/rc.d/puma.conf +10 -0
  15. data/{tools → docs}/jungle/upstart/README.md +0 -0
  16. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  17. data/{tools → docs}/jungle/upstart/puma.conf +1 -1
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +38 -0
  20. data/docs/restart.md +41 -0
  21. data/docs/signals.md +57 -3
  22. data/docs/systemd.md +228 -0
  23. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  24. data/ext/puma_http11/extconf.rb +16 -0
  25. data/ext/puma_http11/http11_parser.c +287 -468
  26. data/ext/puma_http11/http11_parser.h +1 -0
  27. data/ext/puma_http11/http11_parser.java.rl +21 -37
  28. data/ext/puma_http11/http11_parser.rl +10 -9
  29. data/ext/puma_http11/http11_parser_common.rl +4 -4
  30. data/ext/puma_http11/mini_ssl.c +159 -10
  31. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  32. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +99 -132
  33. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
  34. data/ext/puma_http11/puma_http11.c +6 -38
  35. data/lib/puma.rb +25 -5
  36. data/lib/puma/accept_nonblock.rb +7 -1
  37. data/lib/puma/app/status.rb +53 -26
  38. data/lib/puma/binder.rb +150 -119
  39. data/lib/puma/cli.rb +56 -38
  40. data/lib/puma/client.rb +277 -80
  41. data/lib/puma/cluster.rb +326 -130
  42. data/lib/puma/commonlogger.rb +21 -20
  43. data/lib/puma/configuration.rb +160 -161
  44. data/lib/puma/const.rb +50 -47
  45. data/lib/puma/control_cli.rb +104 -63
  46. data/lib/puma/detect.rb +13 -1
  47. data/lib/puma/dsl.rb +463 -114
  48. data/lib/puma/events.rb +22 -13
  49. data/lib/puma/io_buffer.rb +9 -5
  50. data/lib/puma/jruby_restart.rb +2 -59
  51. data/lib/puma/launcher.rb +195 -105
  52. data/lib/puma/minissl.rb +110 -4
  53. data/lib/puma/minissl/context_builder.rb +76 -0
  54. data/lib/puma/null_io.rb +9 -14
  55. data/lib/puma/plugin.rb +32 -12
  56. data/lib/puma/plugin/tmp_restart.rb +19 -6
  57. data/lib/puma/rack/builder.rb +7 -5
  58. data/lib/puma/rack/urlmap.rb +11 -8
  59. data/lib/puma/rack_default.rb +2 -0
  60. data/lib/puma/reactor.rb +242 -32
  61. data/lib/puma/runner.rb +41 -30
  62. data/lib/puma/server.rb +265 -183
  63. data/lib/puma/single.rb +22 -63
  64. data/lib/puma/state_file.rb +9 -2
  65. data/lib/puma/thread_pool.rb +179 -68
  66. data/lib/puma/util.rb +3 -11
  67. data/lib/rack/handler/puma.rb +60 -11
  68. data/tools/Dockerfile +16 -0
  69. data/tools/trickletest.rb +1 -2
  70. metadata +35 -99
  71. data/COPYING +0 -55
  72. data/Gemfile +0 -13
  73. data/Manifest.txt +0 -79
  74. data/Rakefile +0 -158
  75. data/docs/config.md +0 -0
  76. data/ext/puma_http11/io_buffer.c +0 -155
  77. data/lib/puma/capistrano.rb +0 -94
  78. data/lib/puma/compat.rb +0 -18
  79. data/lib/puma/convenient.rb +0 -23
  80. data/lib/puma/daemon_ext.rb +0 -31
  81. data/lib/puma/delegation.rb +0 -11
  82. data/lib/puma/java_io_buffer.rb +0 -45
  83. data/lib/puma/rack/backports/uri/common_18.rb +0 -56
  84. data/lib/puma/rack/backports/uri/common_192.rb +0 -52
  85. data/lib/puma/rack/backports/uri/common_193.rb +0 -29
  86. data/lib/puma/tcp_logger.rb +0 -32
  87. data/puma.gemspec +0 -52
  88. data/tools/jungle/README.md +0 -9
  89. data/tools/jungle/init.d/README.md +0 -54
  90. data/tools/jungle/init.d/puma +0 -394
  91. data/tools/jungle/init.d/run-puma +0 -3
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Puma
2
4
  IS_JRUBY = defined?(JRUBY_VERSION)
3
5
 
@@ -5,7 +7,17 @@ module Puma
5
7
  IS_JRUBY
6
8
  end
7
9
 
10
+ IS_WINDOWS = RUBY_PLATFORM =~ /mswin|ming|cygwin/
11
+
8
12
  def self.windows?
9
- RUBY_PLATFORM =~ /mswin32|ming32/
13
+ IS_WINDOWS
14
+ end
15
+
16
+ def self.mri?
17
+ RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?
18
+ end
19
+
20
+ def self.forkable?
21
+ ::Process.respond_to?(:fork)
10
22
  end
11
23
  end
@@ -1,27 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'puma/const'
4
+
1
5
  module Puma
2
- # The methods that are available for use inside the config file.
6
+ # The methods that are available for use inside the configuration file.
7
+ # These same methods are used in Puma cli and the rack handler
8
+ # internally.
9
+ #
10
+ # Used manually (via CLI class):
11
+ #
12
+ # config = Configuration.new({}) do |user_config|
13
+ # user_config.port 3001
14
+ # end
15
+ # config.load
16
+ #
17
+ # puts config.options[:binds]
18
+ # "tcp://127.0.0.1:3001"
19
+ #
20
+ # Used to load file:
21
+ #
22
+ # $ cat puma_config.rb
23
+ # port 3002
3
24
  #
25
+ # config = Configuration.new(config_file: "puma_config.rb")
26
+ # config.load
27
+ #
28
+ # puts config.options[:binds]
29
+ # # => "tcp://127.0.0.1:3002"
30
+ #
31
+ # You can also find many examples being used by the test suite in
32
+ # +test/config+.
4
33
  class DSL
5
34
  include ConfigDefault
6
35
 
7
- def self.load(options, cfg, path)
8
- d = new(options, cfg)
9
- d._load_from(path)
10
-
11
- options
12
- ensure
13
- d._offer_plugins
14
- end
15
-
16
36
  def initialize(options, config)
17
- @config = config
37
+ @config = config
18
38
  @options = options
19
39
 
20
40
  @plugins = []
21
41
  end
22
42
 
23
43
  def _load_from(path)
24
- instance_eval(File.read(path), path, 1) if path
44
+ if path
45
+ @path = path
46
+ instance_eval(File.read(path), path, 1)
47
+ end
25
48
  ensure
26
49
  _offer_plugins
27
50
  end
@@ -37,10 +60,12 @@ module Puma
37
60
  @plugins.clear
38
61
  end
39
62
 
40
- def _run(&blk)
41
- blk.call self
42
- ensure
43
- _offer_plugins
63
+ def set_default_host(host)
64
+ @options[:default_host] = host
65
+ end
66
+
67
+ def default_host
68
+ @options[:default_host] || Configuration::DefaultTCPHost
44
69
  end
45
70
 
46
71
  def inject(&blk)
@@ -57,9 +82,22 @@ module Puma
57
82
  @plugins << @config.load_plugin(name)
58
83
  end
59
84
 
60
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
61
- # be the app itself.
85
+ # Use an object or block as the rack application. This allows the
86
+ # configuration file to be the application itself.
62
87
  #
88
+ # @example
89
+ # app do |env|
90
+ # body = 'Hello, World!'
91
+ #
92
+ # [
93
+ # 200,
94
+ # {
95
+ # 'Content-Type' => 'text/plain',
96
+ # 'Content-Length' => body.length.to_s
97
+ # },
98
+ # [body]
99
+ # ]
100
+ # end
63
101
  def app(obj=nil, &block)
64
102
  obj ||= block
65
103
 
@@ -68,9 +106,20 @@ module Puma
68
106
  @options[:app] = obj
69
107
  end
70
108
 
71
- # Start the Puma control rack app on +url+. This app can be communicated
72
- # with to control the main server.
109
+ # Start the Puma control rack application on +url+. This application can
110
+ # be communicated with to control the main server. Additionally, you can
111
+ # provide an authentication token, so all requests to the control server
112
+ # will need to include that token as a query parameter. This allows for
113
+ # simple authentication.
114
+ #
115
+ # Check out {Puma::App::Status} to see what the app has available.
73
116
  #
117
+ # @example
118
+ # activate_control_app 'unix:///var/run/pumactl.sock'
119
+ # @example
120
+ # activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
121
+ # @example
122
+ # activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
74
123
  def activate_control_app(url="auto", opts={})
75
124
  if url == "auto"
76
125
  path = Configuration.temp_path
@@ -81,7 +130,12 @@ module Puma
81
130
  end
82
131
 
83
132
  if opts[:no_token]
84
- auth_token = :none
133
+ # We need to use 'none' rather than :none because this value will be
134
+ # passed on to an instance of OptionParser, which doesn't support
135
+ # symbols as option values.
136
+ #
137
+ # See: https://github.com/puma/puma/issues/1193#issuecomment-305995488
138
+ auth_token = 'none'
85
139
  else
86
140
  auth_token = opts[:auth_token]
87
141
  auth_token ||= Configuration.random_token
@@ -92,76 +146,153 @@ module Puma
92
146
  end
93
147
 
94
148
  # Load additional configuration from a file
149
+ # Files get loaded later via Configuration#load
95
150
  def load(file)
96
- _ary(:config_files) << file
151
+ @options[:config_files] ||= []
152
+ @options[:config_files] << file
97
153
  end
98
154
 
99
- # Bind the server to +url+. tcp:// and unix:// are the only accepted
100
- # protocols.
155
+ # Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
156
+ # accepted protocols. Multiple urls can be bound to, calling `bind` does
157
+ # not overwrite previous bindings.
158
+ #
159
+ # The default is "tcp://0.0.0.0:9292".
101
160
  #
161
+ # You can use query parameters within the url to specify options:
162
+ #
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+.
169
+ #
170
+ # @example Backlog depth
171
+ # bind 'unix:///var/run/puma.sock?backlog=512'
172
+ # @example SSL cert
173
+ # bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
174
+ # @example Disable optimization for low latency
175
+ # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
+ # @example Socket permissions
177
+ # bind 'unix:///var/run/puma.sock?umask=0111'
102
178
  def bind(url)
103
- _ary(:binds) << url
179
+ @options[:binds] ||= []
180
+ @options[:binds] << url
181
+ end
182
+
183
+ def clear_binds!
184
+ @options[:binds] = []
104
185
  end
105
186
 
106
187
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
107
188
  #
189
+ # @example
190
+ # port 9292
108
191
  def port(port, host=nil)
109
- host ||= Configuration::DefaultTCPHost
192
+ host ||= default_host
110
193
  bind "tcp://#{host}:#{port}"
111
194
  end
112
195
 
196
+ # Define how long persistent connections can be idle before Puma closes
197
+ # them.
198
+ def persistent_timeout(seconds)
199
+ @options[:persistent_timeout] = Integer(seconds)
200
+ end
201
+
202
+ # Define how long the tcp socket stays open, if no data has been received.
203
+ def first_data_timeout(seconds)
204
+ @options[:first_data_timeout] = Integer(seconds)
205
+ end
206
+
113
207
  # Work around leaky apps that leave garbage in Thread locals
114
- # across requests
115
- #
208
+ # across requests.
116
209
  def clean_thread_locals(which=true)
117
210
  @options[:clean_thread_locals] = which
118
211
  end
119
212
 
120
- # Daemonize the server into the background. Highly suggest that
121
- # this be combined with +pidfile+ and +stdout_redirect+.
122
- def daemonize(which=true)
123
- @options[:daemon] = which
124
- end
125
-
126
213
  # When shutting down, drain the accept socket of pending
127
- # connections and proces them. This loops over the accept
214
+ # connections and process them. This loops over the accept
128
215
  # socket until there are no more read events and then stops
129
216
  # looking and waits for the requests to finish.
130
217
  def drain_on_shutdown(which=true)
131
218
  @options[:drain_on_shutdown] = which
132
219
  end
133
220
 
134
- # Set the environment in which the Rack's app will run.
221
+ # Set the environment in which the rack's app will run. The value must be
222
+ # a string.
223
+ #
224
+ # The default is "development".
225
+ #
226
+ # @example
227
+ # environment 'production'
135
228
  def environment(environment)
136
229
  @options[:environment] = environment
137
230
  end
138
231
 
232
+ # How long to wait for threads to stop when shutting them
233
+ # down. Defaults to :forever. Specifying :immediately will cause
234
+ # Puma to kill the threads immediately. Otherwise the value
235
+ # is the number of seconds to wait.
236
+ #
237
+ # Puma always waits a few seconds after killing a thread for it to try
238
+ # to finish up it's work, even in :immediately mode.
239
+ def force_shutdown_after(val=:forever)
240
+ i = case val
241
+ when :forever
242
+ -1
243
+ when :immediately
244
+ 0
245
+ else
246
+ Float(val)
247
+ end
248
+
249
+ @options[:force_shutdown_after] = i
250
+ end
251
+
139
252
  # Code to run before doing a restart. This code should
140
- # close logfiles, database connections, etc.
253
+ # close log files, database connections, etc.
141
254
  #
142
255
  # This can be called multiple times to add code each time.
143
256
  #
257
+ # @example
258
+ # on_restart do
259
+ # puts 'On restart...'
260
+ # end
144
261
  def on_restart(&block)
145
- _ary(:on_restart) << block
262
+ @options[:on_restart] ||= []
263
+ @options[:on_restart] << block
146
264
  end
147
265
 
148
- # Command to use to restart puma. This should be just how to
149
- # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
150
- # to puma, as those are the same as the original process.
266
+ # Command to use to restart Puma. This should be just how to
267
+ # load Puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
268
+ # to Puma, as those are the same as the original process.
151
269
  #
270
+ # @example
271
+ # restart_command '/u/app/lolcat/bin/restart_puma'
152
272
  def restart_command(cmd)
153
273
  @options[:restart_cmd] = cmd.to_s
154
274
  end
155
275
 
156
- # Store the pid of the server in the file at +path+.
276
+ # Store the pid of the server in the file at "path".
277
+ #
278
+ # @example
279
+ # pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
157
280
  def pidfile(path)
158
281
  @options[:pidfile] = path.to_s
159
282
  end
160
283
 
161
- # Disable request logging.
284
+ # Disable request logging, if this isn't used it'll be enabled by default.
285
+ #
286
+ # @example
287
+ # quiet
288
+ def quiet(which=true)
289
+ @options[:log_requests] = !which
290
+ end
291
+
292
+ # Enable request logging
162
293
  #
163
- def quiet
164
- @options[:quiet] = true
294
+ def log_requests(which=true)
295
+ @options[:log_requests] = which
165
296
  end
166
297
 
167
298
  # Show debugging info
@@ -172,26 +303,44 @@ module Puma
172
303
 
173
304
  # Load +path+ as a rackup file.
174
305
  #
306
+ # The default is "config.ru".
307
+ #
308
+ # @example
309
+ # rackup '/u/apps/lolcat/config.ru'
175
310
  def rackup(path)
176
- @options[:rackup] = path.to_s
311
+ @options[:rackup] ||= path.to_s
177
312
  end
178
313
 
179
- # Run Puma in TCP mode
180
- #
181
- def tcp_mode!
182
- @options[:mode] = :tcp
314
+ def early_hints(answer=true)
315
+ @options[:early_hints] = answer
183
316
  end
184
317
 
185
- # Redirect STDOUT and STDERR to files specified.
318
+ # Redirect STDOUT and STDERR to files specified. The +append+ parameter
319
+ # specifies whether the output is appended, the default is +false+.
320
+ #
321
+ # @example
322
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr'
323
+ # @example
324
+ # stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr', true
186
325
  def stdout_redirect(stdout=nil, stderr=nil, append=false)
187
326
  @options[:redirect_stdout] = stdout
188
327
  @options[:redirect_stderr] = stderr
189
328
  @options[:redirect_append] = append
190
329
  end
191
330
 
331
+ def log_formatter(&block)
332
+ @options[:log_formatter] = block
333
+ end
334
+
192
335
  # Configure +min+ to be the minimum number of threads to use to answer
193
336
  # requests and +max+ the maximum.
194
337
  #
338
+ # The default is "0, 16".
339
+ #
340
+ # @example
341
+ # threads 0, 16
342
+ # @example
343
+ # threads 5, 5
195
344
  def threads(min, max)
196
345
  min = Integer(min)
197
346
  max = Integer(max)
@@ -207,107 +356,213 @@ module Puma
207
356
  @options[:max_threads] = max
208
357
  end
209
358
 
359
+ # Instead of "bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'" you
360
+ # can also use the "ssl_bind" option.
361
+ #
362
+ # @example
363
+ # ssl_bind '127.0.0.1', '9292', {
364
+ # cert: path_to_cert,
365
+ # key: path_to_key,
366
+ # ssl_cipher_filter: cipher_filter, # optional
367
+ # verify_mode: verify_mode, # default 'none'
368
+ # }
369
+ # @example For JRuby additional keys are required: keystore & keystore_pass.
370
+ # ssl_bind '127.0.0.1', '9292', {
371
+ # cert: path_to_cert,
372
+ # key: path_to_key,
373
+ # ssl_cipher_filter: cipher_filter, # optional
374
+ # verify_mode: verify_mode, # default 'none'
375
+ # keystore: path_to_keystore,
376
+ # keystore_pass: password
377
+ # }
210
378
  def ssl_bind(host, port, opts)
379
+ verify = opts.fetch(:verify_mode, 'none').to_s
380
+ no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
381
+ no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
382
+ ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
383
+
211
384
  if defined?(JRUBY_VERSION)
212
385
  keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
213
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
386
+ 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}"
214
387
  else
215
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
388
+ ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
389
+ 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}"
216
390
  end
217
391
  end
218
392
 
219
393
  # Use +path+ as the file to store the server info state. This is
220
- # used by pumactl to query and control the server.
394
+ # used by +pumactl+ to query and control the server.
221
395
  #
396
+ # @example
397
+ # state_path '/u/apps/lolcat/tmp/pids/puma.state'
222
398
  def state_path(path)
223
399
  @options[:state] = path.to_s
224
400
  end
225
401
 
226
- # *Cluster mode only* How many worker processes to run.
402
+ # Use +permission+ to restrict permissions for the state file.
403
+ #
404
+ # @example
405
+ # state_permission 0600
406
+ def state_permission(permission)
407
+ @options[:state_permission] = permission
408
+ end
409
+
410
+ # How many worker processes to run. Typically this is set to
411
+ # the number of available cores.
412
+ #
413
+ # The default is 0.
227
414
  #
415
+ # @note Cluster mode only.
228
416
  def workers(count)
229
417
  @options[:workers] = count.to_i
230
418
  end
231
419
 
232
- # *Cluster mode only* Code to run immediately before master process
420
+ # Code to run immediately before master process
233
421
  # forks workers (once on boot). These hooks can block if necessary
234
- # to wait for background operations unknown to puma to finish before
422
+ # to wait for background operations unknown to Puma to finish before
235
423
  # the process terminates.
236
- # This can be used to close any connections to remote servers (database, redis, ...)
237
- # that were opened when preloading the code
424
+ # This can be used to close any connections to remote servers (database,
425
+ # Redis, ...) that were opened when preloading the code.
238
426
  #
239
- # This can be called multiple times to add hooks.
427
+ # This can be called multiple times to add several hooks.
240
428
  #
429
+ # @note Cluster mode only.
430
+ # @example
431
+ # before_fork do
432
+ # puts "Starting workers..."
433
+ # end
241
434
  def before_fork(&block)
242
- _ary(:before_fork) << block
435
+ @options[:before_fork] ||= []
436
+ @options[:before_fork] << block
243
437
  end
244
438
 
245
- # *Cluster mode only* Code to run immediately before a worker shuts
246
- # down (after it has finished processing HTTP requests). These hooks
247
- # can block if necessary to wait for background operations unknown
248
- # to puma to finish before the process terminates.
439
+ # Code to run in a worker when it boots to setup
440
+ # the process before booting the app.
249
441
  #
250
- # This can be called multiple times to add hooks.
442
+ # This can be called multiple times to add several hooks.
251
443
  #
252
- def on_worker_shutdown(&block)
253
- _ary(:before_worker_shutdown) << block
444
+ # @note Cluster mode only.
445
+ # @example
446
+ # on_worker_fork do
447
+ # puts 'Before worker fork...'
448
+ # end
449
+ def on_worker_boot(&block)
450
+ @options[:before_worker_boot] ||= []
451
+ @options[:before_worker_boot] << block
254
452
  end
255
453
 
256
- # *Cluster mode only* Code to run when a worker boots to setup
257
- # the process before booting the app.
454
+ # Code to run immediately before a worker shuts
455
+ # down (after it has finished processing HTTP requests). These hooks
456
+ # can block if necessary to wait for background operations unknown
457
+ # to Puma to finish before the process terminates.
258
458
  #
259
- # This can be called multiple times to add hooks.
459
+ # This can be called multiple times to add several hooks.
260
460
  #
261
- def on_worker_boot(&block)
262
- _ary(:before_worker_boot) << block
461
+ # @note Cluster mode only.
462
+ # @example
463
+ # on_worker_shutdown do
464
+ # puts 'On worker shutdown...'
465
+ # end
466
+ def on_worker_shutdown(&block)
467
+ @options[:before_worker_shutdown] ||= []
468
+ @options[:before_worker_shutdown] << block
263
469
  end
264
470
 
265
- # *Cluster mode only* Code to run when a master process is
266
- # about to create the worker by forking itself.
471
+ # Code to run in the master right before a worker is started. The worker's
472
+ # index is passed as an argument.
267
473
  #
268
- # This can be called multiple times to add hooks.
474
+ # This can be called multiple times to add several hooks.
269
475
  #
476
+ # @note Cluster mode only.
477
+ # @example
478
+ # on_worker_fork do
479
+ # puts 'Before worker fork...'
480
+ # end
270
481
  def on_worker_fork(&block)
271
- _ary(:before_worker_fork) << block
482
+ @options[:before_worker_fork] ||= []
483
+ @options[:before_worker_fork] << block
272
484
  end
273
485
 
274
- # *Cluster mode only* Code to run when a worker boots to setup
275
- # the process after booting the app.
486
+ # Code to run in the master after a worker has been started. The worker's
487
+ # index is passed as an argument.
276
488
  #
277
- # This can be called multiple times to add hooks.
489
+ # This is called everytime a worker is to be started.
278
490
  #
279
- def after_worker_boot(&block)
280
- _ary(:after_worker_fork) << block
491
+ # @note Cluster mode only.
492
+ # @example
493
+ # after_worker_fork do
494
+ # puts 'After worker fork...'
495
+ # end
496
+ def after_worker_fork(&block)
497
+ @options[:after_worker_fork] ||= []
498
+ @options[:after_worker_fork] = block
281
499
  end
282
500
 
283
- # The directory to operate out of.
284
- def directory(dir)
285
- @options[:directory] = dir.to_s
501
+ alias_method :after_worker_boot, :after_worker_fork
286
502
 
287
- worker_directory dir
503
+ # When `fork_worker` is enabled, code to run in Worker 0
504
+ # before all other workers are re-forked from this process,
505
+ # after the server has temporarily stopped serving requests
506
+ # (once per complete refork cycle).
507
+ #
508
+ # This can be used to trigger extra garbage-collection to maximize
509
+ # copy-on-write efficiency, or close any connections to remote servers
510
+ # (database, Redis, ...) that were opened while the server was running.
511
+ #
512
+ # This can be called multiple times to add several hooks.
513
+ #
514
+ # @note Cluster mode with `fork_worker` enabled only.
515
+ # @example
516
+ # on_refork do
517
+ # 3.times {GC.start}
518
+ # end
519
+
520
+ def on_refork(&block)
521
+ @options[:before_refork] ||= []
522
+ @options[:before_refork] << block
288
523
  end
289
524
 
290
- # Set the directory for workers to start in
291
- def worker_directory(dir)
292
- @options[:worker_directory] = dir.to_s
525
+ # Code to run out-of-band when the worker is idle.
526
+ # These hooks run immediately after a request has finished
527
+ # processing and there are no busy threads on the worker.
528
+ # The worker doesn't accept new requests until this code finishes.
529
+ #
530
+ # This hook is useful for running out-of-band garbage collection
531
+ # or scheduling asynchronous tasks to execute after a response.
532
+ #
533
+ # This can be called multiple times to add several hooks.
534
+ def out_of_band(&block)
535
+ @options[:out_of_band] ||= []
536
+ @options[:out_of_band] << block
293
537
  end
294
538
 
295
- # Run the app as a raw TCP app instead of an HTTP rack app
296
- def tcp_mode
297
- @options[:mode] = :tcp
539
+ # The directory to operate out of.
540
+ #
541
+ # The default is the current directory.
542
+ #
543
+ # @example
544
+ # directory '/u/apps/lolcat'
545
+ def directory(dir)
546
+ @options[:directory] = dir.to_s
298
547
  end
299
548
 
300
- # *Cluster mode only* Preload the application before starting
301
- # the workers and setting up the listen ports. This conflicts
302
- # with using the phased restart feature, you can't use both.
549
+ # Preload the application before starting the workers; this conflicts with
550
+ # phased restart feature. This is off by default.
303
551
  #
552
+ # @note Cluster mode only.
553
+ # @example
554
+ # preload_app!
304
555
  def preload_app!(answer=true)
305
556
  @options[:preload_app] = answer
306
557
  end
307
558
 
308
- # Use +obj+ or +block+ as the low level error handler. This allows a config file to
309
- # change the default error on the server.
559
+ # Use +obj+ or +block+ as the low level error handler. This allows the
560
+ # configuration file to change the default error on the server.
310
561
  #
562
+ # @example
563
+ # lowlevel_error_handler do |err|
564
+ # [200, {}, ["error page"]]
565
+ # end
311
566
  def lowlevel_error_handler(obj=nil, &block)
312
567
  obj ||= block
313
568
  raise "Provide either a #call'able or a block" unless obj
@@ -317,40 +572,102 @@ module Puma
317
572
  # This option is used to allow your app and its gems to be
318
573
  # properly reloaded when not using preload.
319
574
  #
320
- # When set, if puma detects that it's been invoked in the
575
+ # When set, if Puma detects that it's been invoked in the
321
576
  # context of Bundler, it will cleanup the environment and
322
577
  # re-run itself outside the Bundler environment, but directly
323
578
  # using the files that Bundler has setup.
324
579
  #
325
- # This means that puma is now decoupled from your Bundler
580
+ # This means that Puma is now decoupled from your Bundler
326
581
  # context and when each worker loads, it will be loading a
327
582
  # new Bundler context and thus can float around as the release
328
583
  # dictates.
584
+ #
585
+ # See also: extra_runtime_dependencies
586
+ #
587
+ # @note This is incompatible with +preload_app!+.
588
+ # @note This is only supported for RubyGems 2.2+
329
589
  def prune_bundler(answer=true)
330
590
  @options[:prune_bundler] = answer
331
591
  end
332
592
 
333
- # Additional text to display in process listing
593
+ # By default, Puma will raise SignalException when SIGTERM is received. In
594
+ # environments where SIGTERM is something expected, you can suppress these
595
+ # with this option.
596
+ #
597
+ # This can be useful for example in Kubernetes, where rolling restart is
598
+ # guaranteed usually on infrastructure level.
599
+ #
600
+ # @example
601
+ # raise_exception_on_sigterm false
602
+ def raise_exception_on_sigterm(answer=true)
603
+ @options[:raise_exception_on_sigterm] = answer
604
+ end
605
+
606
+ # When using prune_bundler, if extra runtime dependencies need to be loaded to
607
+ # initialize your app, then this setting can be used. This includes any Puma plugins.
608
+ #
609
+ # Before bundler is pruned, the gem names supplied will be looked up in the bundler
610
+ # context and then loaded again after bundler is pruned.
611
+ # Only applies if prune_bundler is used.
612
+ #
613
+ # @example
614
+ # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
615
+ # @example
616
+ # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
617
+ def extra_runtime_dependencies(answer = [])
618
+ @options[:extra_runtime_dependencies] = Array(answer)
619
+ end
620
+
621
+ # Additional text to display in process listing.
622
+ #
623
+ # If you do not specify a tag, Puma will infer it. If you do not want Puma
624
+ # to add a tag, use an empty string.
625
+ #
626
+ # @example
627
+ # tag 'app name'
628
+ # @example
629
+ # tag ''
334
630
  def tag(string)
335
631
  @options[:tag] = string.to_s
336
632
  end
337
633
 
338
- # *Cluster mode only* Set the timeout for workers in seconds
339
- # When set the master process will terminate any workers
340
- # that have not checked in within the given +timeout+.
341
- # This mitigates hung processes. Default value is 60 seconds.
634
+ # Verifies that all workers have checked in to the master process within
635
+ # the given timeout. If not the worker process will be restarted. This is
636
+ # not a request timeout, it is to protect against a hung or dead process.
637
+ # Setting this value will not protect against slow requests.
638
+ #
639
+ # The minimum value is 6 seconds, the default value is 60 seconds.
640
+ #
641
+ # @note Cluster mode only.
642
+ # @example
643
+ # worker_timeout 60
342
644
  def worker_timeout(timeout)
645
+ timeout = Integer(timeout)
646
+ min = Const::WORKER_CHECK_INTERVAL
647
+
648
+ if timeout <= min
649
+ raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
650
+ end
651
+
343
652
  @options[:worker_timeout] = timeout
344
653
  end
345
654
 
346
- # *Cluster mode only* Set the timeout for workers to boot
655
+ # Change the default worker timeout for booting.
656
+ #
657
+ # If unspecified, this defaults to the value of worker_timeout.
658
+ #
659
+ # @note Cluster mode only.
660
+ # @example:
661
+ # worker_boot_timeout 60
347
662
  def worker_boot_timeout(timeout)
348
- @options[:worker_boot_timeout] = timeout
663
+ @options[:worker_boot_timeout] = Integer(timeout)
349
664
  end
350
665
 
351
- # *Cluster mode only* Set the timeout for worker shutdown
666
+ # Set the timeout for worker shutdown
667
+ #
668
+ # @note Cluster mode only.
352
669
  def worker_shutdown_timeout(timeout)
353
- @options[:worker_shutdown_timeout] = timeout
670
+ @options[:worker_shutdown_timeout] = Integer(timeout)
354
671
  end
355
672
 
356
673
  # When set to true (the default), workers accept all requests
@@ -365,7 +682,7 @@ module Puma
365
682
  # Note that setting this to false disables HTTP keepalive and
366
683
  # slow clients will occupy a handler thread while the request
367
684
  # is being sent. A reverse proxy, such as nginx, can handle
368
- # slow clients and queue requests before they reach puma.
685
+ # slow clients and queue requests before they reach Puma.
369
686
  def queue_requests(answer=true)
370
687
  @options[:queue_requests] = answer
371
688
  end
@@ -377,6 +694,16 @@ module Puma
377
694
  @options[:shutdown_debug] = val
378
695
  end
379
696
 
697
+
698
+ # Attempts to route traffic to less-busy workers by causing them to delay
699
+ # listening on the socket, allowing workers which are not processing any
700
+ # requests to pick up new requests first.
701
+ #
702
+ # Only works on MRI. For all other interpreters, this setting does nothing.
703
+ def wait_for_less_busy_worker(val=0.005)
704
+ @options[:wait_for_less_busy_worker] = val.to_f
705
+ end
706
+
380
707
  # Control how the remote address of the connection is set. This
381
708
  # is configurable because to calculate the true socket peer address
382
709
  # a kernel syscall is required which for very fast rack handlers
@@ -394,7 +721,7 @@ module Puma
394
721
  # is used, allowing headers such as X-Forwarded-For
395
722
  # to be used as well.
396
723
  # * Any string - this allows you to hardcode remote address to any value
397
- # you wish. Because puma never uses this field anyway, it's
724
+ # you wish. Because Puma never uses this field anyway, it's
398
725
  # format is entirely in your hands.
399
726
  def set_remote_address(val=:socket)
400
727
  case val
@@ -409,7 +736,7 @@ module Puma
409
736
  when Hash
410
737
  if hdr = val[:header]
411
738
  @options[:remote_address] = :header
412
- @options[:remote_address_header] = "HTTP_" + hdr.upcase.gsub("-", "_")
739
+ @options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
413
740
  else
414
741
  raise "Invalid value for set_remote_address - #{val.inspect}"
415
742
  end
@@ -418,10 +745,32 @@ module Puma
418
745
  end
419
746
  end
420
747
 
421
- private
748
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
749
+ # This option is similar to `preload_app` because the app is preloaded before forking,
750
+ # but it is compatible with phased restart.
751
+ #
752
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
753
+ # in a running app.
754
+ #
755
+ # A refork will automatically trigger once after the specified number of requests
756
+ # (default 1000), or pass 0 to disable auto refork.
757
+ #
758
+ # @note Cluster mode only.
759
+ def fork_worker(after_requests=1000)
760
+ @options[:fork_worker] = Integer(after_requests)
761
+ end
422
762
 
423
- def _ary(key)
424
- (@options.cur[key] ||= [])
763
+ # When enabled, Puma will GC 4 times before forking workers.
764
+ # If available (Ruby 2.7+), we will also call GC.compact.
765
+ # Not recommended for non-MRI Rubies.
766
+ #
767
+ # Based on the work of Koichi Sasada and Aaron Patterson, this option may
768
+ # decrease memory utilization of preload-enabled cluster-mode Pumas. It will
769
+ # also increase time to boot and fork. See your logs for details on how much
770
+ # time this adds to your boot process. For most apps, it will be less than one
771
+ # second.
772
+ def nakayoshi_fork(enabled=false)
773
+ @options[:nakayoshi_fork] = enabled
425
774
  end
426
775
  end
427
776
  end