puma 4.1.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +149 -10
  3. data/LICENSE +23 -20
  4. data/README.md +30 -46
  5. data/docs/architecture.md +3 -3
  6. data/docs/deployment.md +9 -3
  7. data/docs/fork_worker.md +31 -0
  8. data/docs/jungle/README.md +13 -0
  9. data/{tools → docs}/jungle/rc.d/README.md +0 -0
  10. data/{tools → docs}/jungle/rc.d/puma +0 -0
  11. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  12. data/{tools → docs}/jungle/upstart/README.md +0 -0
  13. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  14. data/{tools → docs}/jungle/upstart/puma.conf +0 -0
  15. data/docs/plugins.md +20 -10
  16. data/docs/signals.md +7 -6
  17. data/docs/systemd.md +1 -63
  18. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  19. data/ext/puma_http11/extconf.rb +6 -0
  20. data/ext/puma_http11/http11_parser.c +40 -63
  21. data/ext/puma_http11/http11_parser.java.rl +21 -37
  22. data/ext/puma_http11/http11_parser.rl +3 -1
  23. data/ext/puma_http11/http11_parser_common.rl +3 -3
  24. data/ext/puma_http11/mini_ssl.c +15 -2
  25. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  26. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  27. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +91 -106
  28. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
  29. data/ext/puma_http11/puma_http11.c +9 -38
  30. data/lib/puma.rb +23 -0
  31. data/lib/puma/app/status.rb +46 -30
  32. data/lib/puma/binder.rb +112 -124
  33. data/lib/puma/cli.rb +11 -15
  34. data/lib/puma/client.rb +250 -209
  35. data/lib/puma/cluster.rb +203 -85
  36. data/lib/puma/commonlogger.rb +2 -2
  37. data/lib/puma/configuration.rb +31 -42
  38. data/lib/puma/const.rb +24 -19
  39. data/lib/puma/control_cli.rb +46 -17
  40. data/lib/puma/detect.rb +17 -0
  41. data/lib/puma/dsl.rb +162 -70
  42. data/lib/puma/error_logger.rb +97 -0
  43. data/lib/puma/events.rb +35 -31
  44. data/lib/puma/io_buffer.rb +9 -2
  45. data/lib/puma/jruby_restart.rb +0 -58
  46. data/lib/puma/launcher.rb +117 -58
  47. data/lib/puma/minissl.rb +60 -18
  48. data/lib/puma/minissl/context_builder.rb +73 -0
  49. data/lib/puma/null_io.rb +1 -1
  50. data/lib/puma/plugin.rb +6 -12
  51. data/lib/puma/rack/builder.rb +0 -4
  52. data/lib/puma/reactor.rb +16 -9
  53. data/lib/puma/runner.rb +11 -32
  54. data/lib/puma/server.rb +173 -193
  55. data/lib/puma/single.rb +7 -64
  56. data/lib/puma/state_file.rb +6 -3
  57. data/lib/puma/thread_pool.rb +104 -81
  58. data/lib/rack/handler/puma.rb +1 -5
  59. data/tools/Dockerfile +16 -0
  60. data/tools/trickletest.rb +0 -1
  61. metadata +23 -24
  62. data/ext/puma_http11/io_buffer.c +0 -155
  63. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  64. data/lib/puma/convenient.rb +0 -25
  65. data/lib/puma/daemon_ext.rb +0 -33
  66. data/lib/puma/delegation.rb +0 -13
  67. data/lib/puma/tcp_logger.rb +0 -41
  68. data/tools/jungle/README.md +0 -19
  69. data/tools/jungle/init.d/README.md +0 -61
  70. data/tools/jungle/init.d/puma +0 -421
  71. data/tools/jungle/init.d/run-puma +0 -18
@@ -3,7 +3,7 @@
3
3
  module Puma
4
4
  # Rack::CommonLogger forwards every request to the given +app+, and
5
5
  # logs a line in the
6
- # {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
6
+ # {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
7
7
  # to the +logger+.
8
8
  #
9
9
  # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
@@ -16,7 +16,7 @@ module Puma
16
16
  # (which is called without arguments in order to make the error appear for
17
17
  # sure)
18
18
  class CommonLogger
19
- # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
19
+ # Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
20
20
  #
21
21
  # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
22
  #
@@ -54,9 +54,7 @@ module Puma
54
54
  attr_reader :user_options, :file_options, :default_options
55
55
 
56
56
  def [](key)
57
- return user_options[key] if user_options.key?(key)
58
- return file_options[key] if file_options.key?(key)
59
- return default_options[key] if default_options.key?(key)
57
+ fetch(key)
60
58
  end
61
59
 
62
60
  def []=(key, value)
@@ -64,7 +62,11 @@ module Puma
64
62
  end
65
63
 
66
64
  def fetch(key, default_value = nil)
67
- self[key] || default_value
65
+ return user_options[key] if user_options.key?(key)
66
+ return file_options[key] if file_options.key?(key)
67
+ return default_options[key] if default_options.key?(key)
68
+
69
+ default_value
68
70
  end
69
71
 
70
72
  def all_of(key)
@@ -106,7 +108,7 @@ module Puma
106
108
  #
107
109
  # It also handles loading plugins.
108
110
  #
109
- # > Note: `:port` and `:host` are not valid keys. By they time they make it to the
111
+ # > Note: `:port` and `:host` are not valid keys. By the time they make it to the
110
112
  # configuration options they are expected to be incorporated into a `:binds` key.
111
113
  # Under the hood the DSL maps `port` and `host` calls to `:binds`
112
114
  #
@@ -137,6 +139,10 @@ module Puma
137
139
  @file_dsl = DSL.new(@options.file_options, self)
138
140
  @default_dsl = DSL.new(@options.default_options, self)
139
141
 
142
+ if !@options[:prune_bundler]
143
+ default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
144
+ end
145
+
140
146
  if block
141
147
  configure(&block)
142
148
  end
@@ -167,22 +173,26 @@ module Puma
167
173
  self
168
174
  end
169
175
 
176
+ # @version 5.0.0
177
+ def default_max_threads
178
+ Puma.mri? ? 5 : 16
179
+ end
180
+
170
181
  def puma_default_options
171
182
  {
172
- :min_threads => 0,
173
- :max_threads => 16,
183
+ :min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
184
+ :max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
174
185
  :log_requests => false,
175
186
  :debug => false,
176
187
  :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
177
- :workers => 0,
178
- :daemon => false,
188
+ :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
179
189
  :mode => :http,
180
190
  :worker_timeout => DefaultWorkerTimeout,
181
191
  :worker_boot_timeout => DefaultWorkerTimeout,
182
192
  :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
183
193
  :remote_address => :socket,
184
194
  :tag => method(:infer_tag),
185
- :environment => -> { ENV['RACK_ENV'] || "development" },
195
+ :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
186
196
  :rackup => DefaultRackup,
187
197
  :logger => STDOUT,
188
198
  :persistent_timeout => Const::PERSISTENT_TIMEOUT,
@@ -245,14 +255,6 @@ module Puma
245
255
  def app
246
256
  found = options[:app] || load_rackup
247
257
 
248
- if @options[:mode] == :tcp
249
- require 'puma/tcp_logger'
250
-
251
- logger = @options[:logger]
252
- quiet = !@options[:log_requests]
253
- return TCPLogger.new(logger, found, quiet)
254
- end
255
-
256
258
  if @options[:log_requests]
257
259
  require 'puma/commonlogger'
258
260
  logger = @options[:logger]
@@ -275,8 +277,15 @@ module Puma
275
277
  @plugins.create name
276
278
  end
277
279
 
278
- def run_hooks(key, arg)
279
- @options.all_of(key).each { |b| b.call arg }
280
+ def run_hooks(key, arg, events)
281
+ @options.all_of(key).each do |b|
282
+ begin
283
+ b.call arg
284
+ rescue => e
285
+ events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
286
+ events.debug e.backtrace.join("\n")
287
+ end
288
+ end
280
289
  end
281
290
 
282
291
  def self.temp_path
@@ -332,29 +341,9 @@ module Puma
332
341
  end
333
342
 
334
343
  def self.random_token
335
- begin
336
- require 'openssl'
337
- rescue LoadError
338
- end
339
-
340
- count = 16
341
-
342
- bytes = nil
343
-
344
- if defined? OpenSSL::Random
345
- bytes = OpenSSL::Random.random_bytes(count)
346
- elsif File.exist?("/dev/urandom")
347
- File.open('/dev/urandom') { |f| bytes = f.read(count) }
348
- end
349
-
350
- if bytes
351
- token = "".dup
352
- bytes.each_byte { |b| token << b.to_s(16) }
353
- else
354
- token = (0..count).to_a.map { rand(255).to_s(16) }.join
355
- end
344
+ require 'securerandom' unless defined?(SecureRandom)
356
345
 
357
- return token
346
+ SecureRandom.hex(16)
358
347
  end
359
348
  end
360
349
  end
@@ -100,8 +100,9 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "4.1.1".freeze
104
- CODE_NAME = "Fourth and One".freeze
103
+ PUMA_VERSION = VERSION = "5.0.0".freeze
104
+ CODE_NAME = "Spoony Bard".freeze
105
+
105
106
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
107
 
107
108
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -118,31 +119,35 @@ module Puma
118
119
  # sending data back
119
120
  WRITE_TIMEOUT = 10
120
121
 
122
+ # How many requests to attempt inline before sending a client back to
123
+ # the reactor to be subject to normal ordering. The idea here is that
124
+ # we amortize the cost of going back to the reactor for a well behaved
125
+ # but very "greedy" client across 10 requests. This prevents a not
126
+ # well behaved client from monopolizing the thread forever.
127
+ MAX_FAST_INLINE = 10
128
+
121
129
  # The original URI requested by the client.
122
130
  REQUEST_URI= 'REQUEST_URI'.freeze
123
131
  REQUEST_PATH = 'REQUEST_PATH'.freeze
124
132
  QUERY_STRING = 'QUERY_STRING'.freeze
133
+ CONTENT_LENGTH = "CONTENT_LENGTH".freeze
125
134
 
126
135
  PATH_INFO = 'PATH_INFO'.freeze
127
136
 
128
137
  PUMA_TMP_BASE = "puma".freeze
129
138
 
130
- # Indicate that we couldn't parse the request
131
- ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n".freeze
132
-
133
- # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
134
- ERROR_404_RESPONSE = "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze
135
-
136
- # The standard empty 408 response for requests that timed out.
137
- ERROR_408_RESPONSE = "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze
138
-
139
- CONTENT_LENGTH = "CONTENT_LENGTH".freeze
140
-
141
- # Indicate that there was an internal error, obviously.
142
- ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze
143
-
144
- # A common header for indicating the server is too busy. Not used yet.
145
- ERROR_503_RESPONSE = "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
139
+ ERROR_RESPONSE = {
140
+ # Indicate that we couldn't parse the request
141
+ 400 => "HTTP/1.1 400 Bad Request\r\n\r\n".freeze,
142
+ # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
143
+ 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze,
144
+ # The standard empty 408 response for requests that timed out.
145
+ 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
146
+ # Indicate that there was an internal error, obviously.
147
+ 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
148
+ # A common header for indicating the server is too busy. Not used yet.
149
+ 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
150
+ }
146
151
 
147
152
  # The basic max request size we'll try to read.
148
153
  CHUNK_SIZE = 16 * 1024
@@ -171,7 +176,6 @@ module Puma
171
176
  PORT_443 = "443".freeze
172
177
  LOCALHOST = "localhost".freeze
173
178
  LOCALHOST_IP = "127.0.0.1".freeze
174
- LOCALHOST_ADDR = "127.0.0.1:0".freeze
175
179
 
176
180
  SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
177
181
  HTTP_11 = "HTTP/1.1".freeze
@@ -224,6 +228,7 @@ module Puma
224
228
  COLON = ": ".freeze
225
229
 
226
230
  NEWLINE = "\n".freeze
231
+ HTTP_INJECTION_REGEX = /[\r\n]/.freeze
227
232
 
228
233
  HIJACK_P = "rack.hijack?".freeze
229
234
  HIJACK = "rack.hijack".freeze
@@ -11,7 +11,10 @@ require 'socket'
11
11
  module Puma
12
12
  class ControlCLI
13
13
 
14
- COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
14
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats thread-backtraces refork}
15
+
16
+ # @version 5.0.0
17
+ PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}
15
18
 
16
19
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
17
20
  @state = nil
@@ -22,6 +25,7 @@ module Puma
22
25
  @control_auth_token = nil
23
26
  @config_file = nil
24
27
  @command = nil
28
+ @environment = ENV['RACK_ENV'] || ENV['RAILS_ENV']
25
29
 
26
30
  @argv = argv.dup
27
31
  @stdout = stdout
@@ -59,6 +63,11 @@ module Puma
59
63
  @config_file = arg
60
64
  end
61
65
 
66
+ o.on "-e", "--environment ENVIRONMENT",
67
+ "The environment to run the Rack app on (default development)" do |arg|
68
+ @environment = arg
69
+ end
70
+
62
71
  o.on_tail("-H", "--help", "Show this message") do
63
72
  @stdout.puts o
64
73
  exit
@@ -75,9 +84,22 @@ module Puma
75
84
 
76
85
  @command = argv.shift
77
86
 
87
+ # check presence of command
88
+ unless @command
89
+ raise "Available commands: #{COMMANDS.join(", ")}"
90
+ end
91
+
92
+ unless COMMANDS.include? @command
93
+ raise "Invalid command: #{@command}"
94
+ end
95
+
78
96
  unless @config_file == '-'
79
- if @config_file.nil? and File.exist?('config/puma.rb')
80
- @config_file = 'config/puma.rb'
97
+ environment = @environment || 'development'
98
+
99
+ if @config_file.nil?
100
+ @config_file = %W(config/puma/#{environment}.rb config/puma.rb).find do |f|
101
+ File.exist?(f)
102
+ end
81
103
  end
82
104
 
83
105
  if @config_file
@@ -89,16 +111,6 @@ module Puma
89
111
  @pidfile ||= config.options[:pidfile]
90
112
  end
91
113
  end
92
-
93
- # check present of command
94
- unless @command
95
- raise "Available commands: #{COMMANDS.join(", ")}"
96
- end
97
-
98
- unless COMMANDS.include? @command
99
- raise "Invalid command: #{@command}"
100
- end
101
-
102
114
  rescue => e
103
115
  @stdout.puts e.message
104
116
  exit 1
@@ -122,7 +134,7 @@ module Puma
122
134
  @pid = sf.pid
123
135
  elsif @pidfile
124
136
  # get pid from pid_file
125
- @pid = File.open(@pidfile).gets.to_i
137
+ File.open(@pidfile) { |f| @pid = f.read.to_i }
126
138
  end
127
139
  end
128
140
 
@@ -131,6 +143,13 @@ module Puma
131
143
 
132
144
  # create server object by scheme
133
145
  server = case uri.scheme
146
+ when "ssl"
147
+ require 'openssl'
148
+ OpenSSL::SSL::SSLSocket.new(
149
+ TCPSocket.new(uri.host, uri.port),
150
+ OpenSSL::SSL::SSLContext.new)
151
+ .tap { |ssl| ssl.sync_close = true } # default is false
152
+ .tap(&:connect)
134
153
  when "tcp"
135
154
  TCPSocket.new uri.host, uri.port
136
155
  when "unix"
@@ -171,10 +190,16 @@ module Puma
171
190
  end
172
191
 
173
192
  message "Command #{@command} sent success"
174
- message response.last if @command == "stats" || @command == "gc-stats"
193
+ message response.last if PRINTABLE_COMMANDS.include?(@command)
175
194
  end
176
195
  ensure
177
- server.close if server && !server.closed?
196
+ if server
197
+ if uri.scheme == "ssl"
198
+ server.sysclose
199
+ else
200
+ server.close unless server.closed?
201
+ end
202
+ end
178
203
  end
179
204
 
180
205
  def send_signal
@@ -215,6 +240,9 @@ module Puma
215
240
 
216
241
  return
217
242
 
243
+ when "refork"
244
+ Process.kill "SIGURG", @pid
245
+
218
246
  else
219
247
  return
220
248
  end
@@ -246,7 +274,7 @@ module Puma
246
274
  exit 1
247
275
  end
248
276
 
249
- private
277
+ private
250
278
  def start
251
279
  require 'puma/cli'
252
280
 
@@ -258,6 +286,7 @@ module Puma
258
286
  run_args += ["--control-url", @control_url] if @control_url
259
287
  run_args += ["--control-token", @control_auth_token] if @control_auth_token
260
288
  run_args += ["-C", @config_file] if @config_file
289
+ run_args += ["-e", @environment] if @environment
261
290
 
262
291
  events = Puma::Events.new @stdout, @stderr
263
292
 
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Puma
4
+ # at present, MiniSSL::Engine is only defined in extension code, not in minissl.rb
5
+ HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
6
+
7
+ def self.ssl?
8
+ HAS_SSL
9
+ end
10
+
4
11
  IS_JRUBY = defined?(JRUBY_VERSION)
5
12
 
6
13
  def self.jruby?
@@ -12,4 +19,14 @@ module Puma
12
19
  def self.windows?
13
20
  IS_WINDOWS
14
21
  end
22
+
23
+ # @version 5.0.0
24
+ def self.mri?
25
+ RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?
26
+ end
27
+
28
+ # @version 5.0.0
29
+ def self.forkable?
30
+ ::Process.respond_to?(:fork)
31
+ end
15
32
  end
@@ -14,22 +14,23 @@ 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
 
@@ -98,6 +99,9 @@ module Puma
98
99
  # [body]
99
100
  # ]
100
101
  # end
102
+ #
103
+ # @see Puma::Configuration#app
104
+ #
101
105
  def app(obj=nil, &block)
102
106
  obj ||= block
103
107
 
@@ -160,12 +164,12 @@ module Puma
160
164
  #
161
165
  # You can use query parameters within the url to specify options:
162
166
  #
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+.
167
+ # * Set the socket backlog depth with +backlog+, default is 1024.
168
+ # * Set up an SSL certificate with +key+ & +cert+.
169
+ # * Set whether to optimize for low latency instead of throughput with
170
+ # +low_latency+, default is to optimize for low latency. This is done
171
+ # via +Socket::TCP_NODELAY+.
172
+ # * Set socket permissions with +umask+.
169
173
  #
170
174
  # @example Backlog depth
171
175
  # bind 'unix:///var/run/puma.sock?backlog=512'
@@ -175,6 +179,9 @@ module Puma
175
179
  # bind 'tcp://0.0.0.0:9292?low_latency=false'
176
180
  # @example Socket permissions
177
181
  # bind 'unix:///var/run/puma.sock?umask=0111'
182
+ # @see Puma::Runner#load_and_bind
183
+ # @see Puma::Cluster#run
184
+ #
178
185
  def bind(url)
179
186
  @options[:binds] ||= []
180
187
  @options[:binds] << url
@@ -193,13 +200,14 @@ module Puma
193
200
  bind "tcp://#{host}:#{port}"
194
201
  end
195
202
 
196
- # Define how long persistent connections can be idle before Puma closes
197
- # them.
203
+ # Define how long persistent connections can be idle before Puma closes them.
204
+ # @see Puma::Server.new
198
205
  def persistent_timeout(seconds)
199
206
  @options[:persistent_timeout] = Integer(seconds)
200
207
  end
201
208
 
202
209
  # Define how long the tcp socket stays open, if no data has been received.
210
+ # @see Puma::Server.new
203
211
  def first_data_timeout(seconds)
204
212
  @options[:first_data_timeout] = Integer(seconds)
205
213
  end
@@ -210,24 +218,11 @@ module Puma
210
218
  @options[:clean_thread_locals] = which
211
219
  end
212
220
 
213
- # Daemonize the server into the background. It's highly recommended to
214
- # use this in combination with +pidfile+ and +stdout_redirect+.
221
+ # When shutting down, drain the accept socket of pending connections and
222
+ # process them. This loops over the accept socket until there are no more
223
+ # read events and then stops looking and waits for the requests to finish.
224
+ # @see Puma::Server#graceful_shutdown
215
225
  #
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
226
  def drain_on_shutdown(which=true)
232
227
  @options[:drain_on_shutdown] = which
233
228
  end
@@ -250,6 +245,7 @@ module Puma
250
245
  #
251
246
  # Puma always waits a few seconds after killing a thread for it to try
252
247
  # to finish up it's work, even in :immediately mode.
248
+ # @see Puma::Server#graceful_shutdown
253
249
  def force_shutdown_after(val=:forever)
254
250
  i = case val
255
251
  when :forever
@@ -257,7 +253,7 @@ module Puma
257
253
  when :immediately
258
254
  0
259
255
  else
260
- Integer(val)
256
+ Float(val)
261
257
  end
262
258
 
263
259
  @options[:force_shutdown_after] = i
@@ -322,20 +318,14 @@ module Puma
322
318
  # @example
323
319
  # rackup '/u/apps/lolcat/config.ru'
324
320
  def rackup(path)
325
- @options[:rackup] = path.to_s
326
- end
327
-
328
- # Run Puma in TCP mode
329
- #
330
- def tcp_mode!
331
- @options[:mode] = :tcp
321
+ @options[:rackup] ||= path.to_s
332
322
  end
333
323
 
334
324
  def early_hints(answer=true)
335
325
  @options[:early_hints] = answer
336
326
  end
337
327
 
338
- # Redirect STDOUT and STDERR to files specified. The +append+ parameter
328
+ # Redirect +STDOUT+ and +STDERR+ to files specified. The +append+ parameter
339
329
  # specifies whether the output is appended, the default is +false+.
340
330
  #
341
331
  # @example
@@ -376,8 +366,8 @@ module Puma
376
366
  @options[:max_threads] = max
377
367
  end
378
368
 
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.
369
+ # Instead of `bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'` you
370
+ # can also use the this method.
381
371
  #
382
372
  # @example
383
373
  # ssl_bind '127.0.0.1', '9292', {
@@ -396,7 +386,7 @@ module Puma
396
386
  # keystore_pass: password
397
387
  # }
398
388
  def ssl_bind(host, port, opts)
399
- verify = opts.fetch(:verify_mode, 'none')
389
+ verify = opts.fetch(:verify_mode, 'none').to_s
400
390
  no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
401
391
  no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
402
392
  ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
@@ -419,12 +409,23 @@ module Puma
419
409
  @options[:state] = path.to_s
420
410
  end
421
411
 
412
+ # Use +permission+ to restrict permissions for the state file.
413
+ #
414
+ # @example
415
+ # state_permission 0600
416
+ # @version 5.0.0
417
+ #
418
+ def state_permission(permission)
419
+ @options[:state_permission] = permission
420
+ end
421
+
422
422
  # How many worker processes to run. Typically this is set to
423
- # to the number of available cores.
423
+ # the number of available cores.
424
424
  #
425
425
  # The default is 0.
426
426
  #
427
427
  # @note Cluster mode only.
428
+ # @see Puma::Cluster
428
429
  def workers(count)
429
430
  @options[:workers] = count.to_i
430
431
  end
@@ -455,8 +456,8 @@ module Puma
455
456
  #
456
457
  # @note Cluster mode only.
457
458
  # @example
458
- # on_worker_fork do
459
- # puts 'Before worker fork...'
459
+ # on_worker_boot do
460
+ # puts 'Before worker boot...'
460
461
  # end
461
462
  def on_worker_boot(&block)
462
463
  @options[:before_worker_boot] ||= []
@@ -512,6 +513,29 @@ module Puma
512
513
 
513
514
  alias_method :after_worker_boot, :after_worker_fork
514
515
 
516
+ # When `fork_worker` is enabled, code to run in Worker 0
517
+ # before all other workers are re-forked from this process,
518
+ # after the server has temporarily stopped serving requests
519
+ # (once per complete refork cycle).
520
+ #
521
+ # This can be used to trigger extra garbage-collection to maximize
522
+ # copy-on-write efficiency, or close any connections to remote servers
523
+ # (database, Redis, ...) that were opened while the server was running.
524
+ #
525
+ # This can be called multiple times to add several hooks.
526
+ #
527
+ # @note Cluster mode with `fork_worker` enabled only.
528
+ # @example
529
+ # on_refork do
530
+ # 3.times {GC.start}
531
+ # end
532
+ # @version 5.0.0
533
+ #
534
+ def on_refork(&block)
535
+ @options[:before_refork] ||= []
536
+ @options[:before_refork] << block
537
+ end
538
+
515
539
  # Code to run out-of-band when the worker is idle.
516
540
  # These hooks run immediately after a request has finished
517
541
  # processing and there are no busy threads on the worker.
@@ -536,17 +560,6 @@ module Puma
536
560
  @options[:directory] = dir.to_s
537
561
  end
538
562
 
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
563
  # Preload the application before starting the workers; this conflicts with
551
564
  # phased restart feature. This is off by default.
552
565
  #
@@ -583,7 +596,10 @@ module Puma
583
596
  # new Bundler context and thus can float around as the release
584
597
  # dictates.
585
598
  #
599
+ # @see extra_runtime_dependencies
600
+ #
586
601
  # @note This is incompatible with +preload_app!+.
602
+ # @note This is only supported for RubyGems 2.2+
587
603
  def prune_bundler(answer=true)
588
604
  @options[:prune_bundler] = answer
589
605
  end
@@ -597,10 +613,30 @@ module Puma
597
613
  #
598
614
  # @example
599
615
  # raise_exception_on_sigterm false
616
+ # @see Puma::Launcher#setup_signals
617
+ # @see Puma::Cluster#setup_signals
618
+ #
600
619
  def raise_exception_on_sigterm(answer=true)
601
620
  @options[:raise_exception_on_sigterm] = answer
602
621
  end
603
622
 
623
+ # When using prune_bundler, if extra runtime dependencies need to be loaded to
624
+ # initialize your app, then this setting can be used. This includes any Puma plugins.
625
+ #
626
+ # Before bundler is pruned, the gem names supplied will be looked up in the bundler
627
+ # context and then loaded again after bundler is pruned.
628
+ # Only applies if prune_bundler is used.
629
+ #
630
+ # @example
631
+ # extra_runtime_dependencies ['gem_name_1', 'gem_name_2']
632
+ # @example
633
+ # extra_runtime_dependencies ['puma_worker_killer', 'puma-heroku']
634
+ # @see Puma::Launcher#extra_runtime_deps_directories
635
+ #
636
+ def extra_runtime_dependencies(answer = [])
637
+ @options[:extra_runtime_dependencies] = Array(answer)
638
+ end
639
+
604
640
  # Additional text to display in process listing.
605
641
  #
606
642
  # If you do not specify a tag, Puma will infer it. If you do not want Puma
@@ -624,6 +660,8 @@ module Puma
624
660
  # @note Cluster mode only.
625
661
  # @example
626
662
  # worker_timeout 60
663
+ # @see Puma::Cluster::Worker#ping_timeout
664
+ #
627
665
  def worker_timeout(timeout)
628
666
  timeout = Integer(timeout)
629
667
  min = Const::WORKER_CHECK_INTERVAL
@@ -640,15 +678,20 @@ module Puma
640
678
  # If unspecified, this defaults to the value of worker_timeout.
641
679
  #
642
680
  # @note Cluster mode only.
643
- # @example:
681
+ #
682
+ # @example
644
683
  # worker_boot_timeout 60
684
+ # @see Puma::Cluster::Worker#ping_timeout
685
+ #
645
686
  def worker_boot_timeout(timeout)
646
687
  @options[:worker_boot_timeout] = Integer(timeout)
647
688
  end
648
689
 
649
- # Set the timeout for worker shutdown
690
+ # Set the timeout for worker shutdown.
650
691
  #
651
692
  # @note Cluster mode only.
693
+ # @see Puma::Cluster::Worker#term
694
+ #
652
695
  def worker_shutdown_timeout(timeout)
653
696
  @options[:worker_shutdown_timeout] = Integer(timeout)
654
697
  end
@@ -666,6 +709,7 @@ module Puma
666
709
  # slow clients will occupy a handler thread while the request
667
710
  # is being sent. A reverse proxy, such as nginx, can handle
668
711
  # slow clients and queue requests before they reach Puma.
712
+ # @see Puma::Server
669
713
  def queue_requests(answer=true)
670
714
  @options[:queue_requests] = answer
671
715
  end
@@ -673,10 +717,25 @@ module Puma
673
717
  # When a shutdown is requested, the backtraces of all the
674
718
  # threads will be written to $stdout. This can help figure
675
719
  # out why shutdown is hanging.
720
+ #
676
721
  def shutdown_debug(val=true)
677
722
  @options[:shutdown_debug] = val
678
723
  end
679
724
 
725
+
726
+ # Attempts to route traffic to less-busy workers by causing them to delay
727
+ # listening on the socket, allowing workers which are not processing any
728
+ # requests to pick up new requests first.
729
+ #
730
+ # Only works on MRI. For all other interpreters, this setting does nothing.
731
+ # @see Puma::Server#handle_servers
732
+ # @see Puma::ThreadPool#wait_for_less_busy_worker
733
+ # @version 5.0.0
734
+ #
735
+ def wait_for_less_busy_worker(val=0.005)
736
+ @options[:wait_for_less_busy_worker] = val.to_f
737
+ end
738
+
680
739
  # Control how the remote address of the connection is set. This
681
740
  # is configurable because to calculate the true socket peer address
682
741
  # a kernel syscall is required which for very fast rack handlers
@@ -684,18 +743,18 @@ module Puma
684
743
  #
685
744
  # There are 4 possible values:
686
745
  #
687
- # * :socket (the default) - read the peername from the socket using the
688
- # syscall. This is the normal behavior.
689
- # * :localhost - set the remote address to "127.0.0.1"
690
- # * header: http_header - set the remote address to the value of the
691
- # provided http header. For instance:
692
- # `set_remote_address header: "X-Real-IP"`.
693
- # Only the first word (as separated by spaces or comma)
694
- # is used, allowing headers such as X-Forwarded-For
695
- # to be used as well.
696
- # * Any string - this allows you to hardcode remote address to any value
697
- # you wish. Because Puma never uses this field anyway, it's
698
- # format is entirely in your hands.
746
+ # 1. **:socket** (the default) - read the peername from the socket using the
747
+ # syscall. This is the normal behavior.
748
+ # 2. **:localhost** - set the remote address to "127.0.0.1"
749
+ # 3. **header: <http_header>**- set the remote address to the value of the
750
+ # provided http header. For instance:
751
+ # `set_remote_address header: "X-Real-IP"`.
752
+ # Only the first word (as separated by spaces or comma) is used, allowing
753
+ # headers such as X-Forwarded-For to be used as well.
754
+ # 4. **\<Any string\>** - this allows you to hardcode remote address to any value
755
+ # you wish. Because Puma never uses this field anyway, it's format is
756
+ # entirely in your hands.
757
+ #
699
758
  def set_remote_address(val=:socket)
700
759
  case val
701
760
  when :socket
@@ -718,5 +777,38 @@ module Puma
718
777
  end
719
778
  end
720
779
 
780
+ # When enabled, workers will be forked from worker 0 instead of from the master process.
781
+ # This option is similar to `preload_app` because the app is preloaded before forking,
782
+ # but it is compatible with phased restart.
783
+ #
784
+ # This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
785
+ # in a running app.
786
+ #
787
+ # A refork will automatically trigger once after the specified number of requests
788
+ # (default 1000), or pass 0 to disable auto refork.
789
+ #
790
+ # @note Cluster mode only.
791
+ # @version 5.0.0
792
+ #
793
+ def fork_worker(after_requests=1000)
794
+ @options[:fork_worker] = Integer(after_requests)
795
+ end
796
+
797
+ # When enabled, Puma will GC 4 times before forking workers.
798
+ # If available (Ruby 2.7+), we will also call GC.compact.
799
+ # Not recommended for non-MRI Rubies.
800
+ #
801
+ # Based on the work of Koichi Sasada and Aaron Patterson, this option may
802
+ # decrease memory utilization of preload-enabled cluster-mode Pumas. It will
803
+ # also increase time to boot and fork. See your logs for details on how much
804
+ # time this adds to your boot process. For most apps, it will be less than one
805
+ # second.
806
+ #
807
+ # @see Puma::Cluster#nakayoshi_gc
808
+ # @version 5.0.0
809
+ #
810
+ def nakayoshi_fork(enabled=true)
811
+ @options[:nakayoshi_fork] = enabled
812
+ end
721
813
  end
722
814
  end