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.

@@ -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.new - @first_term_sent) > @options[:worker_shutdown_timeout]
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.new
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
- @options[:before_worker_fork].each { |h| h.call(idx) }
116
+ @launcher.config.run_hooks :before_worker_fork, idx
116
117
 
117
118
  pid = fork { worker(idx, master) }
118
- @cli.debug "Spawned worker: #{pid}"
119
+ debug "Spawned worker: #{pid}"
119
120
  @workers << Worker.new(idx, pid, @phase, @options)
120
- @options[:after_worker_boot].each { |h| h.call }
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
- hooks = @options[:before_worker_boot]
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
- io << payload
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
- hooks = @options[:before_worker_shutdown]
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 @cli.config.app_configured?
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
- @cli.binder.parse @options[:binds], self
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
- @cli.write_state
397
+ @launcher.write_state
394
398
 
395
399
  @master_read, @worker_write = read, @wakeup
396
400
 
397
- hooks = @options[:before_fork]
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
- @cli.events.fire_on_booted!
409
+ @launcher.events.fire_on_booted!
407
410
 
408
411
  begin
409
412
  while @status == :run
@@ -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 initialize(options)
18
- @cli_options = options
121
+ def self.from_file(path)
122
+ cfg = new
19
123
 
20
- @conf = {}
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
- @options = {}
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
- @conf.merge! @cli_options
59
- DSL.load(@conf, @cli_options[:config_file])
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
- # Load the options in the right priority
62
- #
63
- @options.merge! default_options
64
- @options.merge! @conf
65
- @options.merge! @cli_options
193
+ files << imp
194
+ elsif files == ["-"]
195
+ files = []
196
+ end
66
197
 
67
- setup_binds
68
- setup_control
69
- @options[:tag] ||= infer_tag
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] || DefaultRackup
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] || STDOUT
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] || STDOUT
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 setup_binds
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
- @options[:control_auth_token] = token
346
+ return token
216
347
  end
217
348
  end
218
349
  end
@@ -99,8 +99,8 @@ module Puma
99
99
  # too taxing on performance.
100
100
  module Const
101
101
 
102
- PUMA_VERSION = VERSION = "2.16.0".freeze
103
- CODE_NAME = "Midwinter Nights Trance".freeze
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