puma 2.11.1 → 2.11.2

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.

@@ -104,6 +104,7 @@ module Puma
104
104
 
105
105
  diff.times do
106
106
  idx = next_worker_index
107
+ @options[:before_worker_fork].each { |h| h.call(idx) }
107
108
 
108
109
  pid = fork { worker(idx, master) }
109
110
  @cli.debug "Spawned worker: #{pid}"
@@ -1,21 +1,16 @@
1
1
  module Puma
2
2
 
3
- # The CLI exports its Configuration object here to allow
4
- # apps to pick it up. An app needs to use it conditionally though
5
- # since it is not set if the app is launched via another
6
- # mechanism than the CLI class.
7
-
8
- class << self
9
- attr_accessor :cli_config
10
- end
11
-
12
- class Configuration
3
+ module ConfigDefault
13
4
  DefaultRackup = "config.ru"
14
5
 
15
6
  DefaultTCPHost = "0.0.0.0"
16
7
  DefaultTCPPort = 9292
17
8
  DefaultWorkerTimeout = 60
18
9
  DefaultWorkerShutdownTimeout = 30
10
+ end
11
+
12
+ class Configuration
13
+ include ConfigDefault
19
14
 
20
15
  def initialize(options)
21
16
  @options = options
@@ -24,6 +19,7 @@ module Puma
24
19
  @options[:on_restart] ||= []
25
20
  @options[:before_worker_shutdown] ||= []
26
21
  @options[:before_worker_boot] ||= []
22
+ @options[:before_worker_fork] ||= []
27
23
  @options[:after_worker_boot] ||= []
28
24
  @options[:worker_timeout] ||= DefaultWorkerTimeout
29
25
  @options[:worker_shutdown_timeout] ||= DefaultWorkerShutdownTimeout
@@ -36,38 +32,11 @@ module Puma
36
32
  end
37
33
 
38
34
  def load
39
- if path = @options[:config_file]
40
- DSL.new(@options)._load_from path
41
- end
42
-
43
- # Rakeup default option support
44
- if host = @options[:Host]
45
- port = @options[:Port] || DefaultTCPPort
46
-
47
- @options[:binds] << "tcp://#{host}:#{port}"
48
- end
49
-
50
- if @options[:binds].empty?
51
- @options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
52
- end
35
+ DSL.load(@options, @options[:config_file])
53
36
 
54
- if @options[:control_url] == "auto"
55
- path = Configuration.temp_path
56
- @options[:control_url] = "unix://#{path}"
57
- @options[:control_url_temp] = path
58
- end
59
-
60
- unless @options[:control_auth_token]
61
- setup_random_token
62
- end
63
-
64
- unless @options[:tag]
65
- @options[:tag] = infer_tag
66
- end
67
- end
68
-
69
- def infer_tag
70
- File.basename Dir.getwd
37
+ setup_binds
38
+ setup_control
39
+ @options[:tag] ||= infer_tag
71
40
  end
72
41
 
73
42
  # Injects the Configuration object into the env
@@ -97,68 +66,21 @@ module Puma
97
66
  # the rackup file, and set @app.
98
67
  #
99
68
  def app
100
- app = @options[:app]
101
-
102
- unless app
103
- unless File.exist?(rackup)
104
- raise "Missing rackup file '#{rackup}'"
105
- end
106
-
107
- app, options = Rack::Builder.parse_file rackup
108
- @options.merge! options
109
-
110
- config_ru_binds = []
111
-
112
- options.each do |key,val|
113
- if key.to_s[0,4] == "bind"
114
- config_ru_binds << val
115
- end
116
- end
117
-
118
- @options[:binds] = config_ru_binds unless config_ru_binds.empty?
119
- end
69
+ found = options[:app] || load_rackup
120
70
 
121
71
  if @options[:mode] == :tcp
122
72
  require 'puma/tcp_logger'
123
73
 
124
74
  logger = @options[:logger] || STDOUT
125
- return TCPLogger.new(logger, app, @options[:quiet])
75
+ return TCPLogger.new(logger, found, @options[:quiet])
126
76
  end
127
77
 
128
78
  if !@options[:quiet] and @options[:environment] == "development"
129
79
  logger = @options[:logger] || STDOUT
130
- app = Rack::CommonLogger.new(app, logger)
80
+ found = Rack::CommonLogger.new(found, logger)
131
81
  end
132
82
 
133
- return ConfigMiddleware.new(self, app)
134
- end
135
-
136
- def setup_random_token
137
- begin
138
- require 'openssl'
139
- rescue LoadError
140
- end
141
-
142
- count = 16
143
-
144
- bytes = nil
145
-
146
- if defined? OpenSSL::Random
147
- bytes = OpenSSL::Random.random_bytes(count)
148
- elsif File.exist?("/dev/urandom")
149
- File.open("/dev/urandom") do |f|
150
- bytes = f.read(count)
151
- end
152
- end
153
-
154
- if bytes
155
- token = ""
156
- bytes.each_byte { |b| token << b.to_s(16) }
157
- else
158
- token = (0..count).to_a.map { rand(255).to_s(16) }.join
159
- end
160
-
161
- @options[:control_auth_token] = token
83
+ ConfigMiddleware.new(self, found)
162
84
  end
163
85
 
164
86
  def self.temp_path
@@ -168,265 +90,77 @@ module Puma
168
90
  "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
169
91
  end
170
92
 
171
- # The methods that are available for use inside the config file.
172
- #
173
- class DSL
174
- def initialize(options)
175
- @options = options
176
- end
177
-
178
- def _load_from(path)
179
- instance_eval File.read(path), path, 1
180
- end
181
-
182
- # Use +obj+ or +block+ as the Rack app. This allows a config file to
183
- # be the app itself.
184
- #
185
- def app(obj=nil, &block)
186
- obj ||= block
93
+ private
187
94
 
188
- raise "Provide either a #call'able or a block" unless obj
189
-
190
- @options[:app] = obj
191
- end
192
-
193
- # Start the Puma control rack app on +url+. This app can be communicated
194
- # with to control the main server.
195
- #
196
- def activate_control_app(url="auto", opts=nil)
197
- @options[:control_url] = url
198
-
199
- if opts
200
- if tok = opts[:auth_token]
201
- @options[:control_auth_token] = tok
202
- end
203
-
204
- if opts[:no_token]
205
- @options[:control_auth_token] = :none
206
- end
207
- end
208
- end
209
-
210
- # Bind the server to +url+. tcp:// and unix:// are the only accepted
211
- # protocols.
212
- #
213
- def bind(url)
214
- @options[:binds] << url
215
- end
216
-
217
- # Define the TCP port to bind to. Use +bind+ for more advanced options.
218
- #
219
- def port(port)
220
- @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
221
- end
222
-
223
- # Work around leaky apps that leave garbage in Thread locals
224
- # across requests
225
- #
226
- def clean_thread_locals(which=true)
227
- @options[:clean_thread_locals] = which
228
- end
229
-
230
- # Daemonize the server into the background. Highly suggest that
231
- # this be combined with +pidfile+ and +stdout_redirect+.
232
- def daemonize(which=true)
233
- @options[:daemon] = which
234
- end
235
-
236
- # When shutting down, drain the accept socket of pending
237
- # connections and proces them. This loops over the accept
238
- # socket until there are no more read events and then stops
239
- # looking and waits for the requests to finish.
240
- def drain_on_shutdown(which=true)
241
- @options[:drain_on_shutdown] = which
242
- end
243
-
244
- # Set the environment in which the Rack's app will run.
245
- def environment(environment)
246
- @options[:environment] = environment
247
- end
248
-
249
- # Code to run before doing a restart. This code should
250
- # close logfiles, database connections, etc.
251
- #
252
- # This can be called multiple times to add code each time.
253
- #
254
- def on_restart(&block)
255
- @options[:on_restart] << block
256
- end
257
-
258
- # Command to use to restart puma. This should be just how to
259
- # load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
260
- # to puma, as those are the same as the original process.
261
- #
262
- def restart_command(cmd)
263
- @options[:restart_cmd] = cmd
264
- end
265
-
266
- # Store the pid of the server in the file at +path+.
267
- def pidfile(path)
268
- @options[:pidfile] = path
269
- end
270
-
271
- # Disable request logging.
272
- #
273
- def quiet
274
- @options[:quiet] = true
275
- end
276
-
277
- # Load +path+ as a rackup file.
278
- #
279
- def rackup(path)
280
- @options[:rackup] = path.to_s
281
- end
282
-
283
- # Redirect STDOUT and STDERR to files specified.
284
- def stdout_redirect(stdout=nil, stderr=nil, append=false)
285
- @options[:redirect_stdout] = stdout
286
- @options[:redirect_stderr] = stderr
287
- @options[:redirect_append] = append
288
- end
289
-
290
- # Configure +min+ to be the minimum number of threads to use to answer
291
- # requests and +max+ the maximum.
292
- #
293
- def threads(min, max)
294
- min = Integer(min)
295
- max = Integer(max)
296
- if min > max
297
- raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
298
- end
299
-
300
- @options[:min_threads] = min
301
- @options[:max_threads] = max
302
- end
303
-
304
- def ssl_bind(host, port, opts)
305
- o = [
306
- "cert=#{opts[:cert]}",
307
- "key=#{opts[:key]}"
308
- ]
95
+ def infer_tag
96
+ File.basename(Dir.getwd)
97
+ end
309
98
 
310
- @options[:binds] << "ssl://#{host}:#{port}?#{o.join('&')}"
311
- end
99
+ def load_rackup
100
+ raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
312
101
 
313
- # Use +path+ as the file to store the server info state. This is
314
- # used by pumactl to query and control the server.
315
- #
316
- def state_path(path)
317
- @options[:state] = path.to_s
318
- end
102
+ rack_app, rack_options = Rack::Builder.parse_file(rackup)
103
+ @options.merge!(rack_options)
319
104
 
320
- # *Cluster mode only* How many worker processes to run.
321
- #
322
- def workers(count)
323
- @options[:workers] = count.to_i
105
+ config_ru_binds = rack_options.each_with_object([]) do |(k, v), b|
106
+ b << v if k.start_with?('bind')
324
107
  end
108
+ @options[:binds] = config_ru_binds unless config_ru_binds.empty?
325
109
 
326
- # *Cluster mode only* Code to run immediately before a worker shuts
327
- # down (after it has finished processing HTTP requests). These hooks
328
- # can block if necessary to wait for background operations unknown
329
- # to puma to finish before the process terminates.
330
- #
331
- # This can be called multiple times to add hooks.
332
- #
333
- def on_worker_shutdown(&block)
334
- @options[:before_worker_shutdown] << block
335
- end
110
+ rack_app
111
+ end
336
112
 
337
- # *Cluster mode only* Code to run when a worker boots to setup
338
- # the process before booting the app.
339
- #
340
- # This can be called multiple times to add hooks.
341
- #
342
- def on_worker_boot(&block)
343
- @options[:before_worker_boot] << block
113
+ def setup_binds
114
+ # Rakeup default option support
115
+ host = @options[:Host]
116
+ if host
117
+ port = @options[:Port] || DefaultTCPPort
118
+ @options[:binds] << "tcp://#{host}:#{port}"
344
119
  end
345
120
 
346
- # *Cluster mode only* Code to run when a worker boots to setup
347
- # the process after booting the app.
348
- #
349
- # This can be called multiple times to add hooks.
350
- #
351
- def after_worker_boot(&block)
352
- @options[:after_worker_boot] << block
121
+ if @options[:binds].empty?
122
+ @options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
353
123
  end
354
124
 
355
- # The directory to operate out of.
356
- def directory(dir)
357
- @options[:directory] = dir.to_s
358
- @options[:worker_directory] = dir.to_s
359
- end
125
+ @options[:binds].uniq!
126
+ end
360
127
 
361
- # Run the app as a raw TCP app instead of an HTTP rack app
362
- def tcp_mode
363
- @options[:mode] = :tcp
128
+ def setup_control
129
+ if @options[:control_url] == 'auto'
130
+ path = Configuration.temp_path
131
+ @options[:control_url] = "unix://#{path}"
132
+ @options[:control_url_temp] = path
364
133
  end
365
134
 
366
- # *Cluster mode only* Preload the application before starting
367
- # the workers and setting up the listen ports. This conflicts
368
- # with using the phased restart feature, you can't use both.
369
- #
370
- def preload_app!(answer=true)
371
- @options[:preload_app] = answer
372
- end
135
+ setup_random_token unless @options[:control_auth_token]
136
+ end
373
137
 
374
- # Use +obj+ or +block+ as the low level error handler. This allows a config file to
375
- # change the default error on the server.
376
- #
377
- def lowlevel_error_handler(obj=nil, &block)
378
- obj ||= block
379
- raise "Provide either a #call'able or a block" unless obj
380
- @options[:lowlevel_error_handler] = obj
138
+ def setup_random_token
139
+ begin
140
+ require 'openssl'
141
+ rescue LoadError
381
142
  end
382
143
 
383
- # This option is used to allow your app and its gems to be
384
- # properly reloaded when not using preload.
385
- #
386
- # When set, if puma detects that it's been invoked in the
387
- # context of Bundler, it will cleanup the environment and
388
- # re-run itself outside the Bundler environment, but directly
389
- # using the files that Bundler has setup.
390
- #
391
- # This means that puma is now decoupled from your Bundler
392
- # context and when each worker loads, it will be loading a
393
- # new Bundler context and thus can float around as the release
394
- # dictates.
395
- def prune_bundler(answer=true)
396
- @options[:prune_bundler] = answer
397
- end
144
+ count = 16
398
145
 
399
- # Additional text to display in process listing
400
- def tag(string)
401
- @options[:tag] = string
402
- end
146
+ bytes = nil
403
147
 
404
- # *Cluster mode only* Set the timeout for workers
405
- def worker_timeout(timeout)
406
- @options[:worker_timeout] = timeout
148
+ if defined? OpenSSL::Random
149
+ bytes = OpenSSL::Random.random_bytes(count)
150
+ elsif File.exist?("/dev/urandom")
151
+ File.open('/dev/urandom') { |f| bytes = f.read(count) }
407
152
  end
408
153
 
409
- # *Cluster mode only* Set the timeout for worker shutdown
410
- def worker_shutdown_timeout(timeout)
411
- @options[:worker_shutdown_timeout] = timeout
154
+ if bytes
155
+ token = ""
156
+ bytes.each_byte { |b| token << b.to_s(16) }
157
+ else
158
+ token = (0..count).to_a.map { rand(255).to_s(16) }.join
412
159
  end
413
160
 
414
- # When set to true (the default), workers accept all requests
415
- # and queue them before passing them to the handlers.
416
- # When set to false, each worker process accepts exactly as
417
- # many requests as it is configured to simultaneously handle.
418
- #
419
- # Queueing requests generally improves performance. In some
420
- # cases, such as a single threaded application, it may be
421
- # better to ensure requests get balanced across workers.
422
- #
423
- # Note that setting this to false disables HTTP keepalive and
424
- # slow clients will occupy a handler thread while the request
425
- # is being sent. A reverse proxy, such as nginx, can handle
426
- # slow clients and queue requests before they reach puma.
427
- def queue_requests(answer=true)
428
- @options[:queue_requests] = answer
429
- end
161
+ @options[:control_auth_token] = token
430
162
  end
431
163
  end
432
164
  end
165
+
166
+ require 'puma/dsl'