puma 5.5.2 → 6.3.0
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.
- checksums.yaml +4 -4
- data/History.md +336 -3
- data/README.md +61 -16
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +4 -4
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -2
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +28 -14
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +135 -23
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +62 -51
- data/lib/puma/cli.rb +19 -20
- data/lib/puma/client.rb +108 -26
- data/lib/puma/cluster/worker.rb +23 -16
- data/lib/puma/cluster/worker_handle.rb +8 -1
- data/lib/puma/cluster.rb +62 -41
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +76 -55
- data/lib/puma/const.rb +133 -97
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +12 -2
- data/lib/puma/dsl.rb +270 -55
- data/lib/puma/error_logger.rb +18 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +114 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +30 -16
- data/lib/puma/minissl.rb +126 -17
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +1 -1
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -161
- data/lib/puma/runner.rb +55 -22
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +91 -94
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/thread_pool.rb +25 -21
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +1 -1
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/cluster/worker.rb
CHANGED
@@ -2,27 +2,29 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Puma::Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class is instantiated by the `Puma::Cluster` and represents a single
|
6
9
|
# worker process.
|
7
10
|
#
|
8
11
|
# At the core of this class is running an instance of `Puma::Server` which
|
9
12
|
# gets created via the `start_server` method from the `Puma::Runner` class
|
10
13
|
# that this inherits from.
|
11
|
-
class Worker < Puma::Runner
|
14
|
+
class Worker < Puma::Runner # :nodoc:
|
12
15
|
attr_reader :index, :master
|
13
16
|
|
14
17
|
def initialize(index:, master:, launcher:, pipes:, server: nil)
|
15
|
-
super
|
18
|
+
super(launcher)
|
16
19
|
|
17
20
|
@index = index
|
18
21
|
@master = master
|
19
|
-
@launcher = launcher
|
20
|
-
@options = launcher.options
|
21
22
|
@check_pipe = pipes[:check_pipe]
|
22
23
|
@worker_write = pipes[:worker_write]
|
23
24
|
@fork_pipe = pipes[:fork_pipe]
|
24
25
|
@wakeup = pipes[:wakeup]
|
25
26
|
@server = server
|
27
|
+
@hook_data = {}
|
26
28
|
end
|
27
29
|
|
28
30
|
def run
|
@@ -33,8 +35,8 @@ module Puma
|
|
33
35
|
Signal.trap "SIGINT", "IGNORE"
|
34
36
|
Signal.trap "SIGCHLD", "DEFAULT"
|
35
37
|
|
36
|
-
|
37
|
-
Puma.set_thread_name "
|
38
|
+
Thread.new do
|
39
|
+
Puma.set_thread_name "wrkr check"
|
38
40
|
@check_pipe.wait_readable
|
39
41
|
log "! Detected parent died, dying"
|
40
42
|
exit! 1
|
@@ -52,13 +54,14 @@ module Puma
|
|
52
54
|
|
53
55
|
# Invoke any worker boot hooks so they can get
|
54
56
|
# things in shape before booting the app.
|
55
|
-
@
|
57
|
+
@config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
|
56
58
|
|
57
59
|
begin
|
58
60
|
server = @server ||= start_server
|
59
61
|
rescue Exception => e
|
60
62
|
log "! Unable to start worker"
|
61
|
-
log e
|
63
|
+
log e
|
64
|
+
log e.backtrace.join("\n ")
|
62
65
|
exit 1
|
63
66
|
end
|
64
67
|
|
@@ -76,15 +79,14 @@ module Puma
|
|
76
79
|
end
|
77
80
|
|
78
81
|
Thread.new do
|
79
|
-
Puma.set_thread_name "
|
82
|
+
Puma.set_thread_name "wrkr fork"
|
80
83
|
while (idx = @fork_pipe.gets)
|
81
84
|
idx = idx.to_i
|
82
85
|
if idx == -1 # stop server
|
83
86
|
if restart_server.length > 0
|
84
87
|
restart_server.clear
|
85
88
|
server.begin_restart(true)
|
86
|
-
@
|
87
|
-
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
89
|
+
@config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
|
88
90
|
end
|
89
91
|
elsif idx == 0 # restart server
|
90
92
|
restart_server << true << false
|
@@ -113,8 +115,13 @@ module Puma
|
|
113
115
|
|
114
116
|
while restart_server.pop
|
115
117
|
server_thread = server.run
|
118
|
+
|
119
|
+
if @log_writer.debug? && index == 0
|
120
|
+
debug_loaded_extensions "Loaded Extensions - worker 0:"
|
121
|
+
end
|
122
|
+
|
116
123
|
stat_thread ||= Thread.new(@worker_write) do |io|
|
117
|
-
Puma.set_thread_name "stat
|
124
|
+
Puma.set_thread_name "stat pld"
|
118
125
|
base_payload = "p#{Process.pid}"
|
119
126
|
|
120
127
|
while true
|
@@ -130,7 +137,7 @@ module Puma
|
|
130
137
|
Puma::Util.purge_interrupt_queue
|
131
138
|
break
|
132
139
|
end
|
133
|
-
sleep
|
140
|
+
sleep @options[:worker_check_interval]
|
134
141
|
end
|
135
142
|
end
|
136
143
|
server_thread.join
|
@@ -138,7 +145,7 @@ module Puma
|
|
138
145
|
|
139
146
|
# Invoke any worker shutdown hooks so they can prevent the worker
|
140
147
|
# exiting until any background operations are completed
|
141
|
-
@
|
148
|
+
@config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
|
142
149
|
ensure
|
143
150
|
@worker_write << "t#{Process.pid}\n" rescue nil
|
144
151
|
@worker_write.close
|
@@ -147,7 +154,7 @@ module Puma
|
|
147
154
|
private
|
148
155
|
|
149
156
|
def spawn_worker(idx)
|
150
|
-
@
|
157
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
|
151
158
|
|
152
159
|
pid = fork do
|
153
160
|
new_worker = Worker.new index: idx,
|
@@ -165,7 +172,7 @@ module Puma
|
|
165
172
|
exit! 1
|
166
173
|
end
|
167
174
|
|
168
|
-
@
|
175
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
|
169
176
|
pid
|
170
177
|
end
|
171
178
|
end
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class represents a worker process from the perspective of the puma
|
6
9
|
# master process. It contains information about the process and its health
|
7
10
|
# and it exposes methods to control the process via IPC. It does not
|
8
11
|
# include the actual logic executed by the worker process itself. For that,
|
9
12
|
# see Puma::Cluster::Worker.
|
10
|
-
class WorkerHandle
|
13
|
+
class WorkerHandle # :nodoc:
|
11
14
|
def initialize(idx, pid, phase, options)
|
12
15
|
@index = idx
|
13
16
|
@pid = pid
|
@@ -40,6 +43,10 @@ module Puma
|
|
40
43
|
@stage = :booted
|
41
44
|
end
|
42
45
|
|
46
|
+
def term!
|
47
|
+
@term = true
|
48
|
+
end
|
49
|
+
|
43
50
|
def term?
|
44
51
|
@term
|
45
52
|
end
|
data/lib/puma/cluster.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require 'time'
|
3
|
+
require_relative 'runner'
|
4
|
+
require_relative 'util'
|
5
|
+
require_relative 'plugin'
|
6
|
+
require_relative 'cluster/worker_handle'
|
7
|
+
require_relative 'cluster/worker'
|
10
8
|
|
11
9
|
module Puma
|
12
10
|
# This class is instantiated by the `Puma::Launcher` and used
|
@@ -17,8 +15,8 @@ module Puma
|
|
17
15
|
# via the `spawn_workers` method call. Each worker will have it's own
|
18
16
|
# instance of a `Puma::Server`.
|
19
17
|
class Cluster < Runner
|
20
|
-
def initialize(
|
21
|
-
super
|
18
|
+
def initialize(launcher)
|
19
|
+
super(launcher)
|
22
20
|
|
23
21
|
@phase = 0
|
24
22
|
@workers = []
|
@@ -27,6 +25,10 @@ module Puma
|
|
27
25
|
@phased_restart = false
|
28
26
|
end
|
29
27
|
|
28
|
+
# Returns the list of cluster worker handles.
|
29
|
+
# @return [Array<Puma::Cluster::WorkerHandle>]
|
30
|
+
attr_reader :workers
|
31
|
+
|
30
32
|
def stop_workers
|
31
33
|
log "- Gracefully shutting down workers..."
|
32
34
|
@workers.each { |x| x.term }
|
@@ -92,7 +94,7 @@ module Puma
|
|
92
94
|
|
93
95
|
# @version 5.0.0
|
94
96
|
def spawn_worker(idx, master)
|
95
|
-
@
|
97
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer)
|
96
98
|
|
97
99
|
pid = fork { worker(idx, master) }
|
98
100
|
if !pid
|
@@ -101,31 +103,49 @@ module Puma
|
|
101
103
|
exit! 1
|
102
104
|
end
|
103
105
|
|
104
|
-
@
|
106
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer)
|
105
107
|
pid
|
106
108
|
end
|
107
109
|
|
108
110
|
def cull_workers
|
109
111
|
diff = @workers.size - @options[:workers]
|
110
112
|
return if diff < 1
|
113
|
+
debug "Culling #{diff} workers"
|
111
114
|
|
112
|
-
|
113
|
-
|
114
|
-
workers_to_cull = @workers[-diff,diff]
|
115
|
-
debug "Workers to cull: #{workers_to_cull.inspect}"
|
115
|
+
workers = workers_to_cull(diff)
|
116
|
+
debug "Workers to cull: #{workers.inspect}"
|
116
117
|
|
117
|
-
|
118
|
+
workers.each do |worker|
|
118
119
|
log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
|
119
120
|
worker.term
|
120
121
|
end
|
121
122
|
end
|
122
123
|
|
124
|
+
def workers_to_cull(diff)
|
125
|
+
workers = @workers.sort_by(&:started_at)
|
126
|
+
|
127
|
+
# In fork_worker mode, worker 0 acts as our master process.
|
128
|
+
# We should avoid culling it to preserve copy-on-write memory gains.
|
129
|
+
workers.reject! { |w| w.index == 0 } if @options[:fork_worker]
|
130
|
+
|
131
|
+
workers[cull_start_index(diff), diff]
|
132
|
+
end
|
133
|
+
|
134
|
+
def cull_start_index(diff)
|
135
|
+
case @options[:worker_culling_strategy]
|
136
|
+
when :oldest
|
137
|
+
0
|
138
|
+
else # :youngest
|
139
|
+
-diff
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
123
143
|
# @!attribute [r] next_worker_index
|
124
144
|
def next_worker_index
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
145
|
+
occupied_positions = @workers.map(&:index)
|
146
|
+
idx = 0
|
147
|
+
idx += 1 until !occupied_positions.include?(idx)
|
148
|
+
idx
|
129
149
|
end
|
130
150
|
|
131
151
|
def all_workers_booted?
|
@@ -135,7 +155,7 @@ module Puma
|
|
135
155
|
def check_workers
|
136
156
|
return if @next_check >= Time.now
|
137
157
|
|
138
|
-
@next_check = Time.now +
|
158
|
+
@next_check = Time.now + @options[:worker_check_interval]
|
139
159
|
|
140
160
|
timeout_workers
|
141
161
|
wait_workers
|
@@ -158,10 +178,10 @@ module Puma
|
|
158
178
|
end
|
159
179
|
end
|
160
180
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
].compact.min
|
181
|
+
t = @workers.reject(&:term?)
|
182
|
+
t.map!(&:ping_timeout)
|
183
|
+
|
184
|
+
@next_check = [t.min, @next_check].compact.min
|
165
185
|
end
|
166
186
|
|
167
187
|
def worker(index, master)
|
@@ -191,8 +211,8 @@ module Puma
|
|
191
211
|
stop
|
192
212
|
end
|
193
213
|
|
194
|
-
def phased_restart
|
195
|
-
return false if @options[:preload_app]
|
214
|
+
def phased_restart(refork = false)
|
215
|
+
return false if @options[:preload_app] && !refork
|
196
216
|
|
197
217
|
@phased_restart = true
|
198
218
|
wakeup!
|
@@ -208,7 +228,7 @@ module Puma
|
|
208
228
|
def stop_blocked
|
209
229
|
@status = :stop if @status == :run
|
210
230
|
wakeup!
|
211
|
-
@control
|
231
|
+
@control&.stop true
|
212
232
|
Process.waitall
|
213
233
|
end
|
214
234
|
|
@@ -230,24 +250,24 @@ module Puma
|
|
230
250
|
old_worker_count = @workers.count { |w| w.phase != @phase }
|
231
251
|
worker_status = @workers.map do |w|
|
232
252
|
{
|
233
|
-
started_at: w.started_at
|
253
|
+
started_at: utc_iso8601(w.started_at),
|
234
254
|
pid: w.pid,
|
235
255
|
index: w.index,
|
236
256
|
phase: w.phase,
|
237
257
|
booted: w.booted?,
|
238
|
-
last_checkin: w.last_checkin
|
258
|
+
last_checkin: utc_iso8601(w.last_checkin),
|
239
259
|
last_status: w.last_status,
|
240
260
|
}
|
241
261
|
end
|
242
262
|
|
243
263
|
{
|
244
|
-
started_at: @started_at
|
264
|
+
started_at: utc_iso8601(@started_at),
|
245
265
|
workers: @workers.size,
|
246
266
|
phase: @phase,
|
247
267
|
booted_workers: worker_status.count { |w| w[:booted] },
|
248
268
|
old_workers: old_worker_count,
|
249
269
|
worker_status: worker_status,
|
250
|
-
}
|
270
|
+
}.merge(super)
|
251
271
|
end
|
252
272
|
|
253
273
|
def preload?
|
@@ -259,7 +279,7 @@ module Puma
|
|
259
279
|
if (worker = @workers.find { |w| w.index == 0 })
|
260
280
|
worker.phase += 1
|
261
281
|
end
|
262
|
-
phased_restart
|
282
|
+
phased_restart(true)
|
263
283
|
end
|
264
284
|
|
265
285
|
# We do this in a separate method to keep the lambda scope
|
@@ -272,7 +292,7 @@ module Puma
|
|
272
292
|
|
273
293
|
# Auto-fork after the specified number of requests.
|
274
294
|
if (fork_requests = @options[:fork_worker].to_i) > 0
|
275
|
-
@
|
295
|
+
@events.register(:ping!) do |w|
|
276
296
|
fork_worker! if w.index == 0 &&
|
277
297
|
w.phase == 0 &&
|
278
298
|
w.last_status[:requests_count] >= fork_requests
|
@@ -354,12 +374,12 @@ module Puma
|
|
354
374
|
else
|
355
375
|
log "* Restarts: (\u2714) hot (\u2714) phased"
|
356
376
|
|
357
|
-
unless @
|
377
|
+
unless @config.app_configured?
|
358
378
|
error "No application configured, nothing to run"
|
359
379
|
exit 1
|
360
380
|
end
|
361
381
|
|
362
|
-
@launcher.binder.parse @options[:binds]
|
382
|
+
@launcher.binder.parse @options[:binds]
|
363
383
|
end
|
364
384
|
|
365
385
|
read, @wakeup = Puma::Util.pipe
|
@@ -391,8 +411,7 @@ module Puma
|
|
391
411
|
|
392
412
|
@master_read, @worker_write = read, @wakeup
|
393
413
|
|
394
|
-
@
|
395
|
-
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
414
|
+
@config.run_hooks(:before_fork, nil, @log_writer)
|
396
415
|
|
397
416
|
spawn_workers
|
398
417
|
|
@@ -440,14 +459,15 @@ module Puma
|
|
440
459
|
workers_not_booted -= 1
|
441
460
|
when "e"
|
442
461
|
# external term, see worker method, Signal.trap "SIGTERM"
|
443
|
-
w.
|
462
|
+
w.term!
|
444
463
|
when "t"
|
445
464
|
w.term unless w.term?
|
446
465
|
when "p"
|
447
466
|
w.ping!(result.sub(/^\d+/,'').chomp)
|
448
|
-
@
|
467
|
+
@events.fire(:ping!, w)
|
449
468
|
if !booted && @workers.none? {|worker| worker.last_status.empty?}
|
450
|
-
@
|
469
|
+
@events.fire_on_booted!
|
470
|
+
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
451
471
|
booted = true
|
452
472
|
end
|
453
473
|
end
|
@@ -457,6 +477,7 @@ module Puma
|
|
457
477
|
end
|
458
478
|
if in_phased_restart && workers_not_booted.zero?
|
459
479
|
@events.fire_on_booted!
|
480
|
+
debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
|
460
481
|
in_phased_restart = false
|
461
482
|
end
|
462
483
|
|
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}[https://httpd.apache.org/docs/
|
6
|
+
# {Apache common log format}[https://httpd.apache.org/docs/2.4/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: https://httpd.apache.org/docs/
|
19
|
+
# Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
|
20
20
|
#
|
21
21
|
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
22
22
|
#
|
@@ -25,10 +25,17 @@ module Puma
|
|
25
25
|
|
26
26
|
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
|
29
|
+
|
30
|
+
CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
|
31
|
+
# Util::HeaderHash allows mixed
|
32
|
+
HTTP_VERSION = Const::HTTP_VERSION
|
33
|
+
HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
|
34
|
+
PATH_INFO = Const::PATH_INFO
|
35
|
+
QUERY_STRING = Const::QUERY_STRING
|
36
|
+
REMOTE_ADDR = Const::REMOTE_ADDR
|
37
|
+
REMOTE_USER = 'REMOTE_USER'
|
38
|
+
REQUEST_METHOD = Const::REQUEST_METHOD
|
32
39
|
|
33
40
|
def initialize(app, logger=nil)
|
34
41
|
@app = app
|
@@ -57,13 +64,13 @@ module Puma
|
|
57
64
|
now = Time.now
|
58
65
|
|
59
66
|
msg = HIJACK_FORMAT % [
|
60
|
-
env[
|
61
|
-
env[
|
62
|
-
now.strftime(
|
67
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
68
|
+
env[REMOTE_USER] || "-",
|
69
|
+
now.strftime(LOG_TIME_FORMAT),
|
63
70
|
env[REQUEST_METHOD],
|
64
71
|
env[PATH_INFO],
|
65
72
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
66
|
-
env[
|
73
|
+
env[HTTP_VERSION],
|
67
74
|
now - began_at ]
|
68
75
|
|
69
76
|
write(msg)
|
@@ -74,13 +81,13 @@ module Puma
|
|
74
81
|
length = extract_content_length(header)
|
75
82
|
|
76
83
|
msg = FORMAT % [
|
77
|
-
env[
|
78
|
-
env[
|
79
|
-
now.strftime(
|
84
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
85
|
+
env[REMOTE_USER] || "-",
|
86
|
+
now.strftime(LOG_TIME_FORMAT),
|
80
87
|
env[REQUEST_METHOD],
|
81
88
|
env[PATH_INFO],
|
82
89
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
83
|
-
env[
|
90
|
+
env[HTTP_VERSION],
|
84
91
|
status.to_s[0..3],
|
85
92
|
length,
|
86
93
|
now - began_at ]
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,20 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require_relative 'rack/builder'
|
4
|
+
require_relative 'plugin'
|
5
|
+
require_relative 'const'
|
6
|
+
# note that dsl is loaded at end of file, requires ConfigDefault constants
|
6
7
|
|
7
8
|
module Puma
|
8
|
-
|
9
|
-
module ConfigDefault
|
10
|
-
DefaultRackup = "config.ru"
|
11
|
-
|
12
|
-
DefaultTCPHost = "0.0.0.0"
|
13
|
-
DefaultTCPPort = 9292
|
14
|
-
DefaultWorkerTimeout = 60
|
15
|
-
DefaultWorkerShutdownTimeout = 30
|
16
|
-
end
|
17
|
-
|
18
9
|
# A class used for storing "leveled" configuration options.
|
19
10
|
#
|
20
11
|
# In this class any "user" specified options take precedence over any
|
@@ -135,7 +126,50 @@ module Puma
|
|
135
126
|
# is done because an environment variable may have been modified while loading
|
136
127
|
# configuration files.
|
137
128
|
class Configuration
|
138
|
-
|
129
|
+
DEFAULTS = {
|
130
|
+
auto_trim_time: 30,
|
131
|
+
binds: ['tcp://0.0.0.0:9292'.freeze],
|
132
|
+
clean_thread_locals: false,
|
133
|
+
debug: false,
|
134
|
+
early_hints: nil,
|
135
|
+
environment: 'development'.freeze,
|
136
|
+
# Number of seconds to wait until we get the first data for the request
|
137
|
+
first_data_timeout: 30,
|
138
|
+
io_selector_backend: :auto,
|
139
|
+
log_requests: false,
|
140
|
+
logger: STDOUT,
|
141
|
+
# How many requests to attempt inline before sending a client back to
|
142
|
+
# the reactor to be subject to normal ordering. The idea here is that
|
143
|
+
# we amortize the cost of going back to the reactor for a well behaved
|
144
|
+
# but very "greedy" client across 10 requests. This prevents a not
|
145
|
+
# well behaved client from monopolizing the thread forever.
|
146
|
+
max_fast_inline: 10,
|
147
|
+
max_threads: Puma.mri? ? 5 : 16,
|
148
|
+
min_threads: 0,
|
149
|
+
mode: :http,
|
150
|
+
mutate_stdout_and_stderr_to_sync_on_write: true,
|
151
|
+
out_of_band: [],
|
152
|
+
# Number of seconds for another request within a persistent session.
|
153
|
+
persistent_timeout: 20,
|
154
|
+
queue_requests: true,
|
155
|
+
rackup: 'config.ru'.freeze,
|
156
|
+
raise_exception_on_sigterm: true,
|
157
|
+
reaping_time: 1,
|
158
|
+
remote_address: :socket,
|
159
|
+
silence_single_worker_warning: false,
|
160
|
+
silence_fork_callback_warning: false,
|
161
|
+
tag: File.basename(Dir.getwd),
|
162
|
+
tcp_host: '0.0.0.0'.freeze,
|
163
|
+
tcp_port: 9292,
|
164
|
+
wait_for_less_busy_worker: 0.005,
|
165
|
+
worker_boot_timeout: 60,
|
166
|
+
worker_check_interval: 5,
|
167
|
+
worker_culling_strategy: :youngest,
|
168
|
+
worker_shutdown_timeout: 30,
|
169
|
+
worker_timeout: 60,
|
170
|
+
workers: 0,
|
171
|
+
http_content_length_limit: nil
|
172
|
+
}
|
139
173
|
|
140
174
|
def initialize(user_options={}, default_options = {}, &block)
|
141
175
|
default_options = self.puma_default_options.merge(default_options)
|
@@ -180,35 +214,22 @@ module Puma
|
|
180
214
|
self
|
181
215
|
end
|
182
216
|
|
183
|
-
|
184
|
-
|
185
|
-
|
217
|
+
def puma_default_options
|
218
|
+
defaults = DEFAULTS.dup
|
219
|
+
puma_options_from_env.each { |k,v| defaults[k] = v if v }
|
220
|
+
defaults
|
186
221
|
end
|
187
222
|
|
188
|
-
def
|
223
|
+
def puma_options_from_env
|
224
|
+
min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
|
225
|
+
max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
|
226
|
+
workers = ENV['WEB_CONCURRENCY']
|
227
|
+
|
189
228
|
{
|
190
|
-
:
|
191
|
-
:
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
195
|
-
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
196
|
-
:silence_single_worker_warning => false,
|
197
|
-
:mode => :http,
|
198
|
-
:worker_timeout => DefaultWorkerTimeout,
|
199
|
-
:worker_boot_timeout => DefaultWorkerTimeout,
|
200
|
-
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
201
|
-
:remote_address => :socket,
|
202
|
-
:tag => method(:infer_tag),
|
203
|
-
:environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
|
204
|
-
:rackup => DefaultRackup,
|
205
|
-
:logger => STDOUT,
|
206
|
-
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
207
|
-
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
208
|
-
:raise_exception_on_sigterm => true,
|
209
|
-
:max_fast_inline => Const::MAX_FAST_INLINE,
|
210
|
-
:io_selector_backend => :auto,
|
211
|
-
:mutate_stdout_and_stderr_to_sync_on_write => true,
|
229
|
+
min_threads: min && Integer(min),
|
230
|
+
max_threads: max && Integer(max),
|
231
|
+
workers: workers && Integer(workers),
|
232
|
+
environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
|
212
233
|
}
|
213
234
|
end
|
214
235
|
|
@@ -224,7 +245,7 @@ module Puma
|
|
224
245
|
return [] if files == ['-']
|
225
246
|
return files if files.any?
|
226
247
|
|
227
|
-
first_default_file = %W(config/puma/#{
|
248
|
+
first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
|
228
249
|
File.exist?(f)
|
229
250
|
end
|
230
251
|
|
@@ -267,7 +288,7 @@ module Puma
|
|
267
288
|
found = options[:app] || load_rackup
|
268
289
|
|
269
290
|
if @options[:log_requests]
|
270
|
-
|
291
|
+
require_relative 'commonlogger'
|
271
292
|
logger = @options[:logger]
|
272
293
|
found = CommonLogger.new(found, logger)
|
273
294
|
end
|
@@ -280,21 +301,25 @@ module Puma
|
|
280
301
|
@options[:environment]
|
281
302
|
end
|
282
303
|
|
283
|
-
def environment_str
|
284
|
-
environment.respond_to?(:call) ? environment.call : environment
|
285
|
-
end
|
286
|
-
|
287
304
|
def load_plugin(name)
|
288
305
|
@plugins.create name
|
289
306
|
end
|
290
307
|
|
291
|
-
|
308
|
+
# @param key [:Symbol] hook to run
|
309
|
+
# @param arg [Launcher, Int] `:on_restart` passes Launcher
|
310
|
+
#
|
311
|
+
def run_hooks(key, arg, log_writer, hook_data = nil)
|
292
312
|
@options.all_of(key).each do |b|
|
293
313
|
begin
|
294
|
-
b
|
314
|
+
if Array === b
|
315
|
+
hook_data[b[1]] ||= Hash.new
|
316
|
+
b[0].call arg, hook_data[b[1]]
|
317
|
+
else
|
318
|
+
b.call arg
|
319
|
+
end
|
295
320
|
rescue => e
|
296
|
-
|
297
|
-
|
321
|
+
log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
322
|
+
log_writer.debug e.backtrace.join("\n")
|
298
323
|
end
|
299
324
|
end
|
300
325
|
end
|
@@ -312,10 +337,6 @@ module Puma
|
|
312
337
|
|
313
338
|
private
|
314
339
|
|
315
|
-
def infer_tag
|
316
|
-
File.basename(Dir.getwd)
|
317
|
-
end
|
318
|
-
|
319
340
|
# Load and use the normal Rack builder if we can, otherwise
|
320
341
|
# fallback to our minimal version.
|
321
342
|
def rack_builder
|
@@ -365,4 +386,4 @@ module Puma
|
|
365
386
|
end
|
366
387
|
end
|
367
388
|
|
368
|
-
|
389
|
+
require_relative 'dsl'
|