puma 6.6.1 → 7.0.3
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.
- checksums.yaml +4 -4
- data/History.md +114 -4
- data/README.md +11 -24
- data/docs/fork_worker.md +5 -5
- data/docs/kubernetes.md +6 -4
- data/docs/restart.md +2 -2
- data/docs/signals.md +9 -9
- data/docs/stats.md +2 -1
- data/ext/puma_http11/extconf.rb +2 -17
- data/ext/puma_http11/mini_ssl.c +0 -5
- data/lib/puma/binder.rb +10 -8
- data/lib/puma/cli.rb +3 -5
- data/lib/puma/client.rb +31 -31
- data/lib/puma/cluster/worker.rb +9 -10
- data/lib/puma/cluster/worker_handle.rb +36 -5
- data/lib/puma/cluster.rb +12 -13
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +88 -43
- data/lib/puma/const.rb +9 -10
- data/lib/puma/control_cli.rb +6 -2
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +108 -81
- data/lib/puma/error_logger.rb +3 -1
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +28 -29
- data/lib/puma/minissl.rb +0 -1
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -4
- data/lib/puma/request.rb +33 -24
- data/lib/puma/runner.rb +8 -17
- data/lib/puma/server.rb +80 -48
- data/lib/puma/single.rb +4 -1
- data/lib/puma/thread_pool.rb +37 -81
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +2 -2
- metadata +2 -2
data/lib/puma/cluster/worker.rb
CHANGED
@@ -110,7 +110,6 @@ module Puma
|
|
110
110
|
begin
|
111
111
|
@worker_write << "#{PIPE_BOOT}#{Process.pid}:#{index}\n"
|
112
112
|
rescue SystemCallError, IOError
|
113
|
-
Puma::Util.purge_interrupt_queue
|
114
113
|
STDERR.puts "Master seems to have exited, exiting."
|
115
114
|
return
|
116
115
|
end
|
@@ -128,16 +127,16 @@ module Puma
|
|
128
127
|
|
129
128
|
while true
|
130
129
|
begin
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
io << payload
|
130
|
+
payload = base_payload.dup
|
131
|
+
|
132
|
+
hsh = server.stats
|
133
|
+
hsh.each do |k, v|
|
134
|
+
payload << %Q! "#{k}":#{v || 0},!
|
135
|
+
end
|
136
|
+
# sub call properly adds 'closing' string
|
137
|
+
io << payload.sub(/,\z/, " }\n")
|
138
|
+
server.reset_max
|
139
139
|
rescue IOError
|
140
|
-
Puma::Util.purge_interrupt_queue
|
141
140
|
break
|
142
141
|
end
|
143
142
|
sleep @options[:worker_check_interval]
|
@@ -4,13 +4,15 @@ module Puma
|
|
4
4
|
class Cluster < Runner
|
5
5
|
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
6
|
|
7
|
-
|
8
7
|
# This class represents a worker process from the perspective of the puma
|
9
8
|
# master process. It contains information about the process and its health
|
10
9
|
# and it exposes methods to control the process via IPC. It does not
|
11
10
|
# include the actual logic executed by the worker process itself. For that,
|
12
11
|
# see Puma::Cluster::Worker.
|
13
12
|
class WorkerHandle # :nodoc:
|
13
|
+
# array of stat 'max' keys
|
14
|
+
WORKER_MAX_KEYS = [:backlog_max, :reactor_max]
|
15
|
+
|
14
16
|
def initialize(idx, pid, phase, options)
|
15
17
|
@index = idx
|
16
18
|
@pid = pid
|
@@ -23,6 +25,7 @@ module Puma
|
|
23
25
|
@last_checkin = Time.now
|
24
26
|
@last_status = {}
|
25
27
|
@term = false
|
28
|
+
@worker_max = Array.new WORKER_MAX_KEYS.length, 0
|
26
29
|
end
|
27
30
|
|
28
31
|
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
|
@@ -51,12 +54,40 @@ module Puma
|
|
51
54
|
@term
|
52
55
|
end
|
53
56
|
|
54
|
-
STATUS_PATTERN = /{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads":(?<max_threads>\d*), "requests_count":(?<requests_count>\d*), "busy_threads":(?<busy_threads>\d*) }/
|
55
|
-
private_constant :STATUS_PATTERN
|
56
|
-
|
57
57
|
def ping!(status)
|
58
|
+
hsh = {}
|
59
|
+
k, v = nil, nil
|
60
|
+
status.tr('}{"', '').strip.split(", ") do |kv|
|
61
|
+
cntr = 0
|
62
|
+
kv.split(':') do |t|
|
63
|
+
if cntr == 0
|
64
|
+
k = t
|
65
|
+
cntr = 1
|
66
|
+
else
|
67
|
+
v = t
|
68
|
+
end
|
69
|
+
end
|
70
|
+
hsh[k.to_sym] = v.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
# check stat max values, we can't signal workers to reset the max values,
|
74
|
+
# so we do so here
|
75
|
+
WORKER_MAX_KEYS.each_with_index do |key, idx|
|
76
|
+
next unless hsh[key]
|
77
|
+
|
78
|
+
if hsh[key] < @worker_max[idx]
|
79
|
+
hsh[key] = @worker_max[idx]
|
80
|
+
else
|
81
|
+
@worker_max[idx] = hsh[key]
|
82
|
+
end
|
83
|
+
end
|
58
84
|
@last_checkin = Time.now
|
59
|
-
@last_status =
|
85
|
+
@last_status = hsh
|
86
|
+
end
|
87
|
+
|
88
|
+
# Resets max values to zero. Called whenever `Cluster#stats` is called
|
89
|
+
def reset_max
|
90
|
+
WORKER_MAX_KEYS.length.times { |idx| @worker_max[idx] = 0 }
|
60
91
|
end
|
61
92
|
|
62
93
|
# @see Puma::Cluster#check_workers
|
data/lib/puma/cluster.rb
CHANGED
@@ -22,6 +22,7 @@ module Puma
|
|
22
22
|
@workers = []
|
23
23
|
@next_check = Time.now
|
24
24
|
|
25
|
+
@worker_max = [] # keeps track of 'max' stat values
|
25
26
|
@phased_restart = false
|
26
27
|
end
|
27
28
|
|
@@ -45,8 +46,7 @@ module Puma
|
|
45
46
|
end
|
46
47
|
|
47
48
|
def start_phased_restart(refork = false)
|
48
|
-
@events.
|
49
|
-
|
49
|
+
@events.fire_before_restart!
|
50
50
|
@phase += 1
|
51
51
|
if refork
|
52
52
|
log "- Starting worker refork, phase: #{@phase}"
|
@@ -268,11 +268,14 @@ module Puma
|
|
268
268
|
end
|
269
269
|
|
270
270
|
# Inside of a child process, this will return all zeroes, as @workers is only populated in
|
271
|
-
# the master process.
|
271
|
+
# the master process. Calling this also resets stat 'max' values to zero.
|
272
272
|
# @!attribute [r] stats
|
273
|
+
# @return [Hash]
|
274
|
+
|
273
275
|
def stats
|
274
276
|
old_worker_count = @workers.count { |w| w.phase != @phase }
|
275
277
|
worker_status = @workers.map do |w|
|
278
|
+
w.reset_max
|
276
279
|
{
|
277
280
|
started_at: utc_iso8601(w.started_at),
|
278
281
|
pid: w.pid,
|
@@ -283,7 +286,6 @@ module Puma
|
|
283
286
|
last_status: w.last_status,
|
284
287
|
}
|
285
288
|
end
|
286
|
-
|
287
289
|
{
|
288
290
|
started_at: utc_iso8601(@started_at),
|
289
291
|
workers: @workers.size,
|
@@ -352,7 +354,7 @@ module Puma
|
|
352
354
|
|
353
355
|
stop_workers
|
354
356
|
stop
|
355
|
-
@events.
|
357
|
+
@events.fire_after_stopped!
|
356
358
|
raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
|
357
359
|
exit 0 # Clean exit, workers were stopped
|
358
360
|
end
|
@@ -369,12 +371,8 @@ module Puma
|
|
369
371
|
|
370
372
|
if preload?
|
371
373
|
# Threads explicitly marked as fork safe will be ignored. Used in Rails,
|
372
|
-
# but may be used by anyone.
|
373
|
-
|
374
|
-
# where calling thread_variable_get on a Process::Waiter will segfault.
|
375
|
-
# We can drop that clause once those versions of Ruby are no longer
|
376
|
-
# supported.
|
377
|
-
fork_safe = ->(t) { !t.is_a?(Process::Waiter) && t.thread_variable_get(:fork_safe) }
|
374
|
+
# but may be used by anyone.
|
375
|
+
fork_safe = ->(t) { t.thread_variable_get(:fork_safe) }
|
378
376
|
|
379
377
|
before = Thread.list.reject(&fork_safe)
|
380
378
|
|
@@ -423,6 +421,7 @@ module Puma
|
|
423
421
|
|
424
422
|
log "Use Ctrl-C to stop"
|
425
423
|
|
424
|
+
warn_ruby_mn_threads
|
426
425
|
single_worker_warning
|
427
426
|
|
428
427
|
redirect_io
|
@@ -511,7 +510,7 @@ module Puma
|
|
511
510
|
end
|
512
511
|
|
513
512
|
if !booted && @workers.none? {|worker| worker.last_status.empty?}
|
514
|
-
@events.
|
513
|
+
@events.fire_after_booted!
|
515
514
|
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
516
515
|
booted = true
|
517
516
|
end
|
@@ -528,7 +527,7 @@ module Puma
|
|
528
527
|
end
|
529
528
|
|
530
529
|
if in_phased_restart && workers_not_booted.zero?
|
531
|
-
@events.
|
530
|
+
@events.fire_after_booted!
|
532
531
|
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
533
532
|
in_phased_restart = false
|
534
533
|
end
|
data/lib/puma/commonlogger.rb
CHANGED
@@ -29,13 +29,13 @@ module Puma
|
|
29
29
|
|
30
30
|
CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
|
31
31
|
# Util::HeaderHash allows mixed
|
32
|
-
HTTP_VERSION = Const::HTTP_VERSION
|
33
32
|
HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
|
34
33
|
PATH_INFO = Const::PATH_INFO
|
35
34
|
QUERY_STRING = Const::QUERY_STRING
|
36
35
|
REMOTE_ADDR = Const::REMOTE_ADDR
|
37
36
|
REMOTE_USER = 'REMOTE_USER'
|
38
37
|
REQUEST_METHOD = Const::REQUEST_METHOD
|
38
|
+
SERVER_PROTOCOL = Const::SERVER_PROTOCOL
|
39
39
|
|
40
40
|
def initialize(app, logger=nil)
|
41
41
|
@app = app
|
@@ -70,7 +70,7 @@ module Puma
|
|
70
70
|
env[REQUEST_METHOD],
|
71
71
|
env[PATH_INFO],
|
72
72
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
73
|
-
env[
|
73
|
+
env[SERVER_PROTOCOL],
|
74
74
|
now - began_at ]
|
75
75
|
|
76
76
|
write(msg)
|
@@ -87,7 +87,7 @@ module Puma
|
|
87
87
|
env[REQUEST_METHOD],
|
88
88
|
env[PATH_INFO],
|
89
89
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
90
|
-
env[
|
90
|
+
env[SERVER_PROTOCOL],
|
91
91
|
status.to_s[0..3],
|
92
92
|
length,
|
93
93
|
now - began_at ]
|
data/lib/puma/configuration.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative 'plugin'
|
4
4
|
require_relative 'const'
|
5
5
|
require_relative 'dsl'
|
6
|
+
require_relative 'events'
|
6
7
|
|
7
8
|
module Puma
|
8
9
|
# A class used for storing "leveled" configuration options.
|
@@ -112,7 +113,7 @@ module Puma
|
|
112
113
|
# config = Configuration.new({}) do |user_config, file_config, default_config|
|
113
114
|
# user_config.port 3003
|
114
115
|
# end
|
115
|
-
# config.
|
116
|
+
# config.clamp
|
116
117
|
# puts config.options[:port]
|
117
118
|
# # => 3003
|
118
119
|
#
|
@@ -125,10 +126,13 @@ module Puma
|
|
125
126
|
# is done because an environment variable may have been modified while loading
|
126
127
|
# configuration files.
|
127
128
|
class Configuration
|
129
|
+
class NotLoadedError < StandardError; end
|
130
|
+
class NotClampedError < StandardError; end
|
131
|
+
|
128
132
|
DEFAULTS = {
|
129
133
|
auto_trim_time: 30,
|
130
134
|
binds: ['tcp://0.0.0.0:9292'.freeze],
|
131
|
-
|
135
|
+
fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
|
132
136
|
debug: false,
|
133
137
|
enable_keep_alives: true,
|
134
138
|
early_hints: nil,
|
@@ -140,19 +144,17 @@ module Puma
|
|
140
144
|
io_selector_backend: :auto,
|
141
145
|
log_requests: false,
|
142
146
|
logger: STDOUT,
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
|
147
|
-
# well behaved client from monopolizing the thread forever.
|
148
|
-
max_fast_inline: 10,
|
147
|
+
# Limits how many requests a keep alive connection can make.
|
148
|
+
# The connection will be closed after it reaches `max_keep_alive`
|
149
|
+
# requests.
|
150
|
+
max_keep_alive: 999,
|
149
151
|
max_threads: Puma.mri? ? 5 : 16,
|
150
152
|
min_threads: 0,
|
151
153
|
mode: :http,
|
152
154
|
mutate_stdout_and_stderr_to_sync_on_write: true,
|
153
155
|
out_of_band: [],
|
154
156
|
# Number of seconds for another request within a persistent session.
|
155
|
-
persistent_timeout:
|
157
|
+
persistent_timeout: 65, # PUMA_PERSISTENT_TIMEOUT
|
156
158
|
queue_requests: true,
|
157
159
|
rackup: 'config.ru'.freeze,
|
158
160
|
raise_exception_on_sigterm: true,
|
@@ -176,24 +178,31 @@ module Puma
|
|
176
178
|
def initialize(user_options={}, default_options = {}, env = ENV, &block)
|
177
179
|
default_options = self.puma_default_options(env).merge(default_options)
|
178
180
|
|
179
|
-
@
|
181
|
+
@_options = UserFileDefaultOptions.new(user_options, default_options)
|
180
182
|
@plugins = PluginLoader.new
|
181
|
-
@
|
182
|
-
@
|
183
|
-
@
|
184
|
-
|
185
|
-
|
186
|
-
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
187
|
-
end
|
183
|
+
@events = @_options[:events] || Events.new
|
184
|
+
@hooks = {}
|
185
|
+
@user_dsl = DSL.new(@_options.user_options, self)
|
186
|
+
@file_dsl = DSL.new(@_options.file_options, self)
|
187
|
+
@default_dsl = DSL.new(@_options.default_options, self)
|
188
188
|
|
189
189
|
@puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
|
190
190
|
|
191
191
|
if block
|
192
192
|
configure(&block)
|
193
193
|
end
|
194
|
+
|
195
|
+
@loaded = false
|
196
|
+
@clamped = false
|
194
197
|
end
|
195
198
|
|
196
|
-
attr_reader :
|
199
|
+
attr_reader :plugins, :events, :hooks
|
200
|
+
|
201
|
+
def options
|
202
|
+
raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
|
203
|
+
|
204
|
+
@_options
|
205
|
+
end
|
197
206
|
|
198
207
|
def configure
|
199
208
|
yield @user_dsl, @file_dsl, @default_dsl
|
@@ -206,7 +215,7 @@ module Puma
|
|
206
215
|
def initialize_copy(other)
|
207
216
|
@conf = nil
|
208
217
|
@cli_options = nil
|
209
|
-
@
|
218
|
+
@_options = @_options.dup
|
210
219
|
end
|
211
220
|
|
212
221
|
def flatten
|
@@ -214,7 +223,7 @@ module Puma
|
|
214
223
|
end
|
215
224
|
|
216
225
|
def flatten!
|
217
|
-
@
|
226
|
+
@_options = @_options.flatten
|
218
227
|
self
|
219
228
|
end
|
220
229
|
|
@@ -227,6 +236,7 @@ module Puma
|
|
227
236
|
def puma_options_from_env(env = ENV)
|
228
237
|
min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
|
229
238
|
max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
|
239
|
+
persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
|
230
240
|
workers = if env['WEB_CONCURRENCY'] == 'auto'
|
231
241
|
require_processor_counter
|
232
242
|
::Concurrent.available_processor_count
|
@@ -237,24 +247,27 @@ module Puma
|
|
237
247
|
{
|
238
248
|
min_threads: min && min != "" && Integer(min),
|
239
249
|
max_threads: max && max != "" && Integer(max),
|
250
|
+
persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
|
240
251
|
workers: workers && workers != "" && Integer(workers),
|
241
252
|
environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
|
242
253
|
}
|
243
254
|
end
|
244
255
|
|
245
256
|
def load
|
257
|
+
@loaded = true
|
246
258
|
config_files.each { |config_file| @file_dsl._load_from(config_file) }
|
247
|
-
|
248
|
-
@options
|
259
|
+
@_options
|
249
260
|
end
|
250
261
|
|
251
262
|
def config_files
|
252
|
-
|
263
|
+
raise NotLoadedError, "ensure load is called before accessing config_files" unless @loaded
|
264
|
+
|
265
|
+
files = @_options.all_of(:config_files)
|
253
266
|
|
254
267
|
return [] if files == ['-']
|
255
268
|
return files if files.any?
|
256
269
|
|
257
|
-
first_default_file = %W(config/puma/#{@
|
270
|
+
first_default_file = %W(config/puma/#{@_options[:environment]}.rb config/puma.rb).find do |f|
|
258
271
|
File.exist?(f)
|
259
272
|
end
|
260
273
|
|
@@ -262,9 +275,16 @@ module Puma
|
|
262
275
|
end
|
263
276
|
|
264
277
|
# Call once all configuration (included from rackup files)
|
265
|
-
# is loaded to
|
278
|
+
# is loaded to finalize defaults and lock in the configuration.
|
279
|
+
#
|
280
|
+
# This also calls load if it hasn't been called yet.
|
266
281
|
def clamp
|
267
|
-
@
|
282
|
+
load unless @loaded
|
283
|
+
set_conditional_default_options
|
284
|
+
@_options.finalize_values
|
285
|
+
@clamped = true
|
286
|
+
warn_hooks
|
287
|
+
options
|
268
288
|
end
|
269
289
|
|
270
290
|
# Injects the Configuration object into the env
|
@@ -283,11 +303,11 @@ module Puma
|
|
283
303
|
# Indicate if there is a properly configured app
|
284
304
|
#
|
285
305
|
def app_configured?
|
286
|
-
|
306
|
+
options[:app] || File.exist?(rackup)
|
287
307
|
end
|
288
308
|
|
289
309
|
def rackup
|
290
|
-
|
310
|
+
options[:rackup]
|
291
311
|
end
|
292
312
|
|
293
313
|
# Load the specified rackup file, pull options from
|
@@ -296,9 +316,9 @@ module Puma
|
|
296
316
|
def app
|
297
317
|
found = options[:app] || load_rackup
|
298
318
|
|
299
|
-
if
|
319
|
+
if options[:log_requests]
|
300
320
|
require_relative 'commonlogger'
|
301
|
-
logger =
|
321
|
+
logger = options[:custom_logger] ? options[:custom_logger] : options[:logger]
|
302
322
|
found = CommonLogger.new(found, logger)
|
303
323
|
end
|
304
324
|
|
@@ -307,7 +327,7 @@ module Puma
|
|
307
327
|
|
308
328
|
# Return which environment we're running in
|
309
329
|
def environment
|
310
|
-
|
330
|
+
options[:environment]
|
311
331
|
end
|
312
332
|
|
313
333
|
def load_plugin(name)
|
@@ -315,18 +335,19 @@ module Puma
|
|
315
335
|
end
|
316
336
|
|
317
337
|
# @param key [:Symbol] hook to run
|
318
|
-
# @param arg [Launcher, Int] `:
|
338
|
+
# @param arg [Launcher, Int] `:before_restart` passes Launcher
|
319
339
|
#
|
320
340
|
def run_hooks(key, arg, log_writer, hook_data = nil)
|
321
341
|
log_writer.debug "Running #{key} hooks"
|
322
342
|
|
323
|
-
|
343
|
+
options.all_of(key).each do |hook_options|
|
324
344
|
begin
|
325
|
-
|
326
|
-
|
327
|
-
|
345
|
+
block = hook_options[:block]
|
346
|
+
if id = hook_options[:id]
|
347
|
+
hook_data[id] ||= Hash.new
|
348
|
+
block.call arg, hook_data[id]
|
328
349
|
else
|
329
|
-
|
350
|
+
block.call arg
|
330
351
|
end
|
331
352
|
rescue => e
|
332
353
|
log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
@@ -336,7 +357,7 @@ module Puma
|
|
336
357
|
end
|
337
358
|
|
338
359
|
def final_options
|
339
|
-
|
360
|
+
options.final_options
|
340
361
|
end
|
341
362
|
|
342
363
|
def self.temp_path
|
@@ -346,6 +367,12 @@ module Puma
|
|
346
367
|
"#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
|
347
368
|
end
|
348
369
|
|
370
|
+
def self.random_token
|
371
|
+
require 'securerandom' unless defined?(SecureRandom)
|
372
|
+
|
373
|
+
SecureRandom.hex(16)
|
374
|
+
end
|
375
|
+
|
349
376
|
private
|
350
377
|
|
351
378
|
def require_processor_counter
|
@@ -386,22 +413,40 @@ module Puma
|
|
386
413
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
387
414
|
rack_options = rack_options || {}
|
388
415
|
|
389
|
-
|
416
|
+
options.file_options.merge!(rack_options)
|
390
417
|
|
391
418
|
config_ru_binds = []
|
392
419
|
rack_options.each do |k, v|
|
393
420
|
config_ru_binds << v if k.to_s.start_with?("bind")
|
394
421
|
end
|
395
422
|
|
396
|
-
|
423
|
+
options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
397
424
|
|
398
425
|
rack_app
|
399
426
|
end
|
400
427
|
|
401
|
-
def
|
402
|
-
|
428
|
+
def set_conditional_default_options
|
429
|
+
@_options.default_options[:preload_app] = !@_options[:prune_bundler] &&
|
430
|
+
(@_options[:workers] > 1) && Puma.forkable?
|
431
|
+
end
|
403
432
|
|
404
|
-
|
433
|
+
def warn_hooks
|
434
|
+
return if options[:workers] > 0
|
435
|
+
return if options[:silence_fork_callback_warning]
|
436
|
+
|
437
|
+
log_writer = LogWriter.stdio
|
438
|
+
@hooks.each_key do |hook|
|
439
|
+
options.all_of(hook).each do |hook_options|
|
440
|
+
next unless hook_options[:cluster_only]
|
441
|
+
|
442
|
+
log_writer.log(<<~MSG.tr("\n", " "))
|
443
|
+
Warning: The code in the `#{hook}` block will not execute
|
444
|
+
in the current Puma configuration. The `#{hook}` block only
|
445
|
+
executes in Puma's cluster mode. To fix this, either remove the
|
446
|
+
`#{hook}` call or increase Puma's worker count above zero.
|
447
|
+
MSG
|
448
|
+
end
|
449
|
+
end
|
405
450
|
end
|
406
451
|
end
|
407
452
|
end
|
data/lib/puma/const.rb
CHANGED
@@ -100,13 +100,11 @@ 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 = "7.0.3"
|
104
|
+
CODE_NAME = "Romantic Warrior"
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
|
107
107
|
|
108
|
-
FAST_TRACK_KA_TIMEOUT = 0.2
|
109
|
-
|
110
108
|
# How long to wait when getting some write blocking on the socket when
|
111
109
|
# sending data back
|
112
110
|
WRITE_TIMEOUT = 10
|
@@ -125,9 +123,9 @@ module Puma
|
|
125
123
|
# Indicate that we couldn't parse the request
|
126
124
|
400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
|
127
125
|
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
128
|
-
404 => "HTTP/1.1 404 Not Found\r\
|
126
|
+
404 => "HTTP/1.1 404 Not Found\r\nconnection: close\r\n\r\n",
|
129
127
|
# The standard empty 408 response for requests that timed out.
|
130
|
-
408 => "HTTP/1.1 408 Request Timeout\r\
|
128
|
+
408 => "HTTP/1.1 408 Request Timeout\r\nconnection: close\r\n\r\n",
|
131
129
|
# Indicate that there was an internal error, obviously.
|
132
130
|
500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
|
133
131
|
# Incorrect or invalid header value
|
@@ -230,6 +228,7 @@ module Puma
|
|
230
228
|
RACK_INPUT = "rack.input"
|
231
229
|
RACK_URL_SCHEME = "rack.url_scheme"
|
232
230
|
RACK_AFTER_REPLY = "rack.after_reply"
|
231
|
+
RACK_RESPONSE_FINISHED = "rack.response_finished"
|
233
232
|
PUMA_SOCKET = "puma.socket"
|
234
233
|
PUMA_CONFIG = "puma.config"
|
235
234
|
PUMA_PEERCERT = "puma.peercert"
|
@@ -252,14 +251,14 @@ module Puma
|
|
252
251
|
KEEP_ALIVE = "keep-alive"
|
253
252
|
|
254
253
|
CONTENT_LENGTH2 = "content-length"
|
255
|
-
CONTENT_LENGTH_S = "
|
254
|
+
CONTENT_LENGTH_S = "content-length: "
|
256
255
|
TRANSFER_ENCODING = "transfer-encoding"
|
257
256
|
TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
|
258
257
|
|
259
|
-
CONNECTION_CLOSE = "
|
260
|
-
CONNECTION_KEEP_ALIVE = "
|
258
|
+
CONNECTION_CLOSE = "connection: close\r\n"
|
259
|
+
CONNECTION_KEEP_ALIVE = "connection: keep-alive\r\n"
|
261
260
|
|
262
|
-
TRANSFER_ENCODING_CHUNKED = "
|
261
|
+
TRANSFER_ENCODING_CHUNKED = "transfer-encoding: chunked\r\n"
|
263
262
|
CLOSE_CHUNKED = "0\r\n\r\n"
|
264
263
|
|
265
264
|
CHUNKED = "chunked"
|
data/lib/puma/control_cli.rb
CHANGED
@@ -124,11 +124,15 @@ module Puma
|
|
124
124
|
end
|
125
125
|
|
126
126
|
if @config_file
|
127
|
+
# needed because neither `Puma::CLI` or `Puma::Server` are loaded
|
128
|
+
require_relative '../puma'
|
129
|
+
|
127
130
|
require_relative 'configuration'
|
128
131
|
require_relative 'log_writer'
|
129
132
|
|
130
133
|
config = Puma::Configuration.new({ config_files: [@config_file] }, {} , env)
|
131
|
-
config.
|
134
|
+
config.clamp
|
135
|
+
|
132
136
|
@state ||= config.options[:state]
|
133
137
|
@control_url ||= config.options[:control_url]
|
134
138
|
@control_auth_token ||= config.options[:control_auth_token]
|
@@ -248,7 +252,7 @@ module Puma
|
|
248
252
|
@stdout.flush unless @stdout.sync
|
249
253
|
return
|
250
254
|
elsif sig.start_with? 'SIG'
|
251
|
-
if Signal.list.key? sig.
|
255
|
+
if Signal.list.key? sig.delete_prefix('SIG')
|
252
256
|
Process.kill sig, @pid
|
253
257
|
else
|
254
258
|
raise "Signal '#{sig}' not available'"
|