puma 2.16.0 → 3.0.0.rc1
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/Manifest.txt +5 -0
- data/README.md +4 -1
- data/ext/puma_http11/http11_parser.java.rl +5 -5
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
- data/lib/puma.rb +1 -0
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/binder.rb +6 -1
- data/lib/puma/cli.rb +125 -494
- data/lib/puma/cluster.rb +21 -18
- data/lib/puma/configuration.rb +189 -58
- data/lib/puma/const.rb +2 -2
- data/lib/puma/control_cli.rb +57 -72
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +6 -0
- data/lib/puma/detect.rb +8 -1
- data/lib/puma/dsl.rb +105 -26
- data/lib/puma/events.rb +5 -0
- data/lib/puma/launcher.rb +397 -0
- data/lib/puma/null_io.rb +15 -0
- data/lib/puma/plugin.rb +91 -0
- data/lib/puma/plugin/tmp_restart.rb +23 -0
- data/lib/puma/runner.rb +19 -14
- data/lib/puma/server.rb +1 -0
- data/lib/puma/single.rb +9 -4
- data/lib/puma/state_file.rb +27 -0
- data/lib/rack/handler/puma.rb +26 -27
- metadata +9 -4
data/lib/puma/cluster.rb
CHANGED
@@ -2,8 +2,8 @@ require 'puma/runner'
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Runner
|
5
|
-
def initialize(cli)
|
6
|
-
super cli
|
5
|
+
def initialize(cli, events)
|
6
|
+
super cli, events
|
7
7
|
|
8
8
|
@phase = 0
|
9
9
|
@workers = []
|
@@ -52,6 +52,7 @@ module Puma
|
|
52
52
|
@options = options
|
53
53
|
@first_term_sent = nil
|
54
54
|
@last_checkin = Time.now
|
55
|
+
@dead = false
|
55
56
|
end
|
56
57
|
|
57
58
|
attr_reader :index, :pid, :phase, :signal, :last_checkin
|
@@ -83,10 +84,10 @@ module Puma
|
|
83
84
|
|
84
85
|
def term
|
85
86
|
begin
|
86
|
-
if @first_term_sent && (Time.
|
87
|
+
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
87
88
|
@signal = "KILL"
|
88
89
|
else
|
89
|
-
@first_term_sent ||= Time.
|
90
|
+
@first_term_sent ||= Time.now
|
90
91
|
end
|
91
92
|
|
92
93
|
Process.kill @signal, @pid
|
@@ -112,12 +113,13 @@ module Puma
|
|
112
113
|
|
113
114
|
diff.times do
|
114
115
|
idx = next_worker_index
|
115
|
-
@
|
116
|
+
@launcher.config.run_hooks :before_worker_fork, idx
|
116
117
|
|
117
118
|
pid = fork { worker(idx, master) }
|
118
|
-
|
119
|
+
debug "Spawned worker: #{pid}"
|
119
120
|
@workers << Worker.new(idx, pid, @phase, @options)
|
120
|
-
|
121
|
+
|
122
|
+
@launcher.config.run_hooks :after_worker_fork, idx
|
121
123
|
end
|
122
124
|
|
123
125
|
if diff > 0
|
@@ -220,8 +222,7 @@ module Puma
|
|
220
222
|
|
221
223
|
# Invoke any worker boot hooks so they can get
|
222
224
|
# things in shape before booting the app.
|
223
|
-
|
224
|
-
hooks.each { |h| h.call(index) }
|
225
|
+
@launcher.config.run_hooks :before_worker_boot, index
|
225
226
|
|
226
227
|
server = start_server
|
227
228
|
|
@@ -241,7 +242,11 @@ module Puma
|
|
241
242
|
|
242
243
|
while true
|
243
244
|
sleep 5
|
244
|
-
|
245
|
+
begin
|
246
|
+
io << payload
|
247
|
+
rescue IOError
|
248
|
+
break
|
249
|
+
end
|
245
250
|
end
|
246
251
|
end
|
247
252
|
|
@@ -249,8 +254,7 @@ module Puma
|
|
249
254
|
|
250
255
|
# Invoke any worker shutdown hooks so they can prevent the worker
|
251
256
|
# exiting until any background operations are completed
|
252
|
-
|
253
|
-
hooks.each { |h| h.call(index) }
|
257
|
+
@launcher.config.run_hooks :before_worker_shutdown, index
|
254
258
|
ensure
|
255
259
|
@worker_write << "t#{Process.pid}\n" rescue nil
|
256
260
|
@worker_write.close
|
@@ -333,12 +337,12 @@ module Puma
|
|
333
337
|
else
|
334
338
|
log "* Phased restart available"
|
335
339
|
|
336
|
-
unless @
|
340
|
+
unless @launcher.config.app_configured?
|
337
341
|
error "No application configured, nothing to run"
|
338
342
|
exit 1
|
339
343
|
end
|
340
344
|
|
341
|
-
@
|
345
|
+
@launcher.binder.parse @options[:binds], self
|
342
346
|
end
|
343
347
|
|
344
348
|
read, @wakeup = Puma::Util.pipe
|
@@ -390,12 +394,11 @@ module Puma
|
|
390
394
|
|
391
395
|
start_control
|
392
396
|
|
393
|
-
@
|
397
|
+
@launcher.write_state
|
394
398
|
|
395
399
|
@master_read, @worker_write = read, @wakeup
|
396
400
|
|
397
|
-
|
398
|
-
hooks.each { |h| h.call }
|
401
|
+
@launcher.config.run_hooks :before_fork, nil
|
399
402
|
|
400
403
|
spawn_workers
|
401
404
|
|
@@ -403,7 +406,7 @@ module Puma
|
|
403
406
|
stop
|
404
407
|
end
|
405
408
|
|
406
|
-
@
|
409
|
+
@launcher.events.fire_on_booted!
|
407
410
|
|
408
411
|
begin
|
409
412
|
while @status == :run
|
data/lib/puma/configuration.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'puma/rack/builder'
|
2
|
+
require 'puma/plugin'
|
2
3
|
|
3
4
|
module Puma
|
4
5
|
|
@@ -11,30 +12,139 @@ module Puma
|
|
11
12
|
DefaultWorkerShutdownTimeout = 30
|
12
13
|
end
|
13
14
|
|
15
|
+
class LeveledOptions
|
16
|
+
def initialize(default={})
|
17
|
+
@cur = {}
|
18
|
+
@set = [@cur]
|
19
|
+
@defaults = default.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize_copy(other)
|
23
|
+
@set = @set.map { |o| o.dup }
|
24
|
+
@cur = @set.last
|
25
|
+
end
|
26
|
+
|
27
|
+
def shift
|
28
|
+
@cur = {}
|
29
|
+
@set << @cur
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](key)
|
33
|
+
@set.each do |o|
|
34
|
+
if o.key? key
|
35
|
+
return o[key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
v = @defaults[key]
|
40
|
+
if v.respond_to? :call
|
41
|
+
v.call
|
42
|
+
else
|
43
|
+
v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :cur
|
48
|
+
|
49
|
+
def all_of(key)
|
50
|
+
all = []
|
51
|
+
|
52
|
+
@set.each do |o|
|
53
|
+
if v = o[key]
|
54
|
+
if v.kind_of? Array
|
55
|
+
all += v
|
56
|
+
else
|
57
|
+
all << v
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
all
|
63
|
+
end
|
64
|
+
|
65
|
+
def []=(key, val)
|
66
|
+
@cur[key] = val
|
67
|
+
end
|
68
|
+
|
69
|
+
def key?(key)
|
70
|
+
@set.each do |o|
|
71
|
+
if o.key? key
|
72
|
+
return true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@default.key? key
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge!(o)
|
80
|
+
o.each do |k,v|
|
81
|
+
@cur[k]= v
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def flatten
|
86
|
+
options = {}
|
87
|
+
|
88
|
+
@set.each do |o|
|
89
|
+
o.each do |k,v|
|
90
|
+
options[k] ||= v
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
options
|
95
|
+
end
|
96
|
+
|
97
|
+
def explain
|
98
|
+
indent = ""
|
99
|
+
|
100
|
+
@set.each do |o|
|
101
|
+
o.keys.sort.each do |k|
|
102
|
+
puts "#{indent}#{k}: #{o[k].inspect}"
|
103
|
+
end
|
104
|
+
|
105
|
+
indent = " #{indent}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def force_defaults
|
110
|
+
@defaults.each do |k,v|
|
111
|
+
if v.respond_to? :call
|
112
|
+
@defaults[k] = v.call
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
14
118
|
class Configuration
|
15
119
|
include ConfigDefault
|
16
120
|
|
17
|
-
def
|
18
|
-
|
121
|
+
def self.from_file(path)
|
122
|
+
cfg = new
|
19
123
|
|
20
|
-
|
21
|
-
@conf[:mode] ||= :http
|
22
|
-
@conf[:binds] ||= []
|
23
|
-
@conf[:on_restart] ||= []
|
24
|
-
@conf[:before_fork] ||= []
|
25
|
-
@conf[:before_worker_shutdown] ||= []
|
26
|
-
@conf[:before_worker_boot] ||= []
|
27
|
-
@conf[:before_worker_fork] ||= []
|
28
|
-
@conf[:after_worker_boot] ||= []
|
29
|
-
@conf[:worker_timeout] ||= DefaultWorkerTimeout
|
30
|
-
@conf[:worker_boot_timeout] ||= @conf[:worker_timeout]
|
31
|
-
@conf[:worker_shutdown_timeout] ||= DefaultWorkerShutdownTimeout
|
32
|
-
@conf[:remote_address] ||= :socket
|
124
|
+
DSL.new(cfg.options, cfg)._load_from path
|
33
125
|
|
34
|
-
|
126
|
+
return cfg
|
127
|
+
end
|
128
|
+
|
129
|
+
def initialize(options={}, &blk)
|
130
|
+
@options = LeveledOptions.new(default_options)
|
131
|
+
@plugins = PluginLoader.new
|
132
|
+
|
133
|
+
# options.each do |k,v|
|
134
|
+
# @options[k] = v
|
135
|
+
# end
|
136
|
+
|
137
|
+
if blk
|
138
|
+
configure(&blk)
|
139
|
+
end
|
35
140
|
end
|
36
141
|
|
37
|
-
attr_reader :options
|
142
|
+
attr_reader :options, :plugins
|
143
|
+
|
144
|
+
def configure(&blk)
|
145
|
+
@options.shift
|
146
|
+
DSL.new(@options, self)._run(&blk)
|
147
|
+
end
|
38
148
|
|
39
149
|
def initialize_copy(other)
|
40
150
|
@conf = nil
|
@@ -42,31 +152,61 @@ module Puma
|
|
42
152
|
@options = @options.dup
|
43
153
|
end
|
44
154
|
|
155
|
+
def flatten
|
156
|
+
dup.flatten!
|
157
|
+
end
|
158
|
+
|
159
|
+
def flatten!
|
160
|
+
@options = @options.flatten
|
161
|
+
self
|
162
|
+
end
|
163
|
+
|
45
164
|
def default_options
|
46
165
|
{
|
47
166
|
:min_threads => 0,
|
48
167
|
:max_threads => 16,
|
49
168
|
:quiet => false,
|
50
169
|
:debug => false,
|
51
|
-
:binds => [],
|
170
|
+
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
52
171
|
:workers => 0,
|
53
172
|
:daemon => false,
|
173
|
+
:mode => :http,
|
174
|
+
:worker_timeout => DefaultWorkerTimeout,
|
175
|
+
:worker_boot_timeout => DefaultWorkerTimeout,
|
176
|
+
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
177
|
+
:remote_address => :socket,
|
178
|
+
:tag => method(:infer_tag),
|
179
|
+
:environment => lambda { ENV['RACK_ENV'] || "development" },
|
180
|
+
:rackup => DefaultRackup,
|
181
|
+
:logger => STDOUT
|
54
182
|
}
|
55
183
|
end
|
56
184
|
|
57
185
|
def load
|
58
|
-
@
|
59
|
-
|
186
|
+
files = @options.all_of(:config_files)
|
187
|
+
|
188
|
+
if files.empty?
|
189
|
+
imp = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find { |f|
|
190
|
+
File.exist?(f)
|
191
|
+
}
|
60
192
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@options.merge! @cli_options
|
193
|
+
files << imp
|
194
|
+
elsif files == ["-"]
|
195
|
+
files = []
|
196
|
+
end
|
66
197
|
|
67
|
-
|
68
|
-
|
69
|
-
|
198
|
+
files.each do |f|
|
199
|
+
@options.shift
|
200
|
+
|
201
|
+
DSL.load @options, self, f
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Call once all configuration (included from rackup files)
|
206
|
+
# is loaded to flesh out any defaults
|
207
|
+
def clamp
|
208
|
+
@options.shift
|
209
|
+
@options.force_defaults
|
70
210
|
end
|
71
211
|
|
72
212
|
# Injects the Configuration object into the env
|
@@ -89,7 +229,7 @@ module Puma
|
|
89
229
|
end
|
90
230
|
|
91
231
|
def rackup
|
92
|
-
@options[:rackup]
|
232
|
+
@options[:rackup]
|
93
233
|
end
|
94
234
|
|
95
235
|
# Load the specified rackup file, pull options from
|
@@ -101,18 +241,31 @@ module Puma
|
|
101
241
|
if @options[:mode] == :tcp
|
102
242
|
require 'puma/tcp_logger'
|
103
243
|
|
104
|
-
logger = @options[:logger]
|
244
|
+
logger = @options[:logger]
|
105
245
|
return TCPLogger.new(logger, found, @options[:quiet])
|
106
246
|
end
|
107
247
|
|
108
248
|
if !@options[:quiet] and @options[:environment] == "development"
|
109
|
-
logger = @options[:logger]
|
249
|
+
logger = @options[:logger]
|
110
250
|
found = CommonLogger.new(found, logger)
|
111
251
|
end
|
112
252
|
|
113
253
|
ConfigMiddleware.new(self, found)
|
114
254
|
end
|
115
255
|
|
256
|
+
# Return which environment we're running in
|
257
|
+
def environment
|
258
|
+
@options[:environment]
|
259
|
+
end
|
260
|
+
|
261
|
+
def load_plugin(name)
|
262
|
+
@plugins.create name
|
263
|
+
end
|
264
|
+
|
265
|
+
def run_hooks(key, arg)
|
266
|
+
@options.all_of(key).each { |b| b.call arg }
|
267
|
+
end
|
268
|
+
|
116
269
|
def self.temp_path
|
117
270
|
require 'tmpdir'
|
118
271
|
|
@@ -152,6 +305,8 @@ module Puma
|
|
152
305
|
def load_rackup
|
153
306
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
154
307
|
|
308
|
+
@options.shift
|
309
|
+
|
155
310
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
156
311
|
@options.merge!(rack_options)
|
157
312
|
|
@@ -159,37 +314,13 @@ module Puma
|
|
159
314
|
rack_options.each do |k, v|
|
160
315
|
config_ru_binds << v if k.to_s.start_with?("bind")
|
161
316
|
end
|
317
|
+
|
162
318
|
@options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
163
319
|
|
164
320
|
rack_app
|
165
321
|
end
|
166
322
|
|
167
|
-
def
|
168
|
-
# Rakeup default option support
|
169
|
-
host = @options[:Host]
|
170
|
-
if host
|
171
|
-
port = @options[:Port] || DefaultTCPPort
|
172
|
-
@options[:binds] << "tcp://#{host}:#{port}"
|
173
|
-
end
|
174
|
-
|
175
|
-
if @options[:binds].empty?
|
176
|
-
@options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
|
177
|
-
end
|
178
|
-
|
179
|
-
@options[:binds].uniq!
|
180
|
-
end
|
181
|
-
|
182
|
-
def setup_control
|
183
|
-
if @options[:control_url] == 'auto'
|
184
|
-
path = Configuration.temp_path
|
185
|
-
@options[:control_url] = "unix://#{path}"
|
186
|
-
@options[:control_url_temp] = path
|
187
|
-
end
|
188
|
-
|
189
|
-
setup_random_token unless @options[:control_auth_token]
|
190
|
-
end
|
191
|
-
|
192
|
-
def setup_random_token
|
323
|
+
def self.random_token
|
193
324
|
begin
|
194
325
|
require 'openssl'
|
195
326
|
rescue LoadError
|
@@ -212,7 +343,7 @@ module Puma
|
|
212
343
|
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
213
344
|
end
|
214
345
|
|
215
|
-
|
346
|
+
return token
|
216
347
|
end
|
217
348
|
end
|
218
349
|
end
|
data/lib/puma/const.rb
CHANGED
@@ -99,8 +99,8 @@ module Puma
|
|
99
99
|
# too taxing on performance.
|
100
100
|
module Const
|
101
101
|
|
102
|
-
PUMA_VERSION = VERSION = "
|
103
|
-
CODE_NAME = "
|
102
|
+
PUMA_VERSION = VERSION = "3.0.0.rc1".freeze
|
103
|
+
CODE_NAME = "Schneems Sleak Shoes".freeze
|
104
104
|
|
105
105
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
106
106
|
|