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.
- checksums.yaml +4 -4
- data/History.md +149 -10
- data/LICENSE +23 -20
- data/README.md +30 -46
- data/docs/architecture.md +3 -3
- data/docs/deployment.md +9 -3
- data/docs/fork_worker.md +31 -0
- data/docs/jungle/README.md +13 -0
- data/{tools → docs}/jungle/rc.d/README.md +0 -0
- data/{tools → docs}/jungle/rc.d/puma +0 -0
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +0 -0
- data/docs/plugins.md +20 -10
- data/docs/signals.md +7 -6
- data/docs/systemd.md +1 -63
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/extconf.rb +6 -0
- data/ext/puma_http11/http11_parser.c +40 -63
- data/ext/puma_http11/http11_parser.java.rl +21 -37
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/ext/puma_http11/http11_parser_common.rl +3 -3
- data/ext/puma_http11/mini_ssl.c +15 -2
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +91 -106
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
- data/ext/puma_http11/puma_http11.c +9 -38
- data/lib/puma.rb +23 -0
- data/lib/puma/app/status.rb +46 -30
- data/lib/puma/binder.rb +112 -124
- data/lib/puma/cli.rb +11 -15
- data/lib/puma/client.rb +250 -209
- data/lib/puma/cluster.rb +203 -85
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +31 -42
- data/lib/puma/const.rb +24 -19
- data/lib/puma/control_cli.rb +46 -17
- data/lib/puma/detect.rb +17 -0
- data/lib/puma/dsl.rb +162 -70
- data/lib/puma/error_logger.rb +97 -0
- data/lib/puma/events.rb +35 -31
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/launcher.rb +117 -58
- data/lib/puma/minissl.rb +60 -18
- data/lib/puma/minissl/context_builder.rb +73 -0
- data/lib/puma/null_io.rb +1 -1
- data/lib/puma/plugin.rb +6 -12
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +16 -9
- data/lib/puma/runner.rb +11 -32
- data/lib/puma/server.rb +173 -193
- data/lib/puma/single.rb +7 -64
- data/lib/puma/state_file.rb +6 -3
- data/lib/puma/thread_pool.rb +104 -81
- data/lib/rack/handler/puma.rb +1 -5
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +23 -24
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/convenient.rb +0 -25
- data/lib/puma/daemon_ext.rb +0 -33
- data/lib/puma/delegation.rb +0 -13
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
data/lib/puma/commonlogger.rb
CHANGED
@@ -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}[
|
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:
|
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
|
#
|
data/lib/puma/configuration.rb
CHANGED
@@ -54,9 +54,7 @@ module Puma
|
|
54
54
|
attr_reader :user_options, :file_options, :default_options
|
55
55
|
|
56
56
|
def [](key)
|
57
|
-
|
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
|
-
|
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
|
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 =>
|
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
|
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
|
-
|
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
|
-
|
346
|
+
SecureRandom.hex(16)
|
358
347
|
end
|
359
348
|
end
|
360
349
|
end
|
data/lib/puma/const.rb
CHANGED
@@ -100,8 +100,9 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "
|
104
|
-
CODE_NAME = "
|
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
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
data/lib/puma/control_cli.rb
CHANGED
@@ -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
|
-
|
80
|
-
|
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
|
-
|
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
|
193
|
+
message response.last if PRINTABLE_COMMANDS.include?(@command)
|
175
194
|
end
|
176
195
|
ensure
|
177
|
-
|
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
|
-
|
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
|
|
data/lib/puma/detect.rb
CHANGED
@@ -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
|
data/lib/puma/dsl.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
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
|
-
#
|
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
|
-
#
|
214
|
-
#
|
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
|
-
|
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]
|
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
|
380
|
-
# can also use the
|
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
|
-
#
|
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
|
-
#
|
459
|
-
# puts 'Before worker
|
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
|
-
#
|
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
|
-
#
|
688
|
-
#
|
689
|
-
#
|
690
|
-
#
|
691
|
-
#
|
692
|
-
#
|
693
|
-
#
|
694
|
-
#
|
695
|
-
#
|
696
|
-
#
|
697
|
-
#
|
698
|
-
#
|
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
|