puma 2.10.2 → 2.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a44132e0d62673bb33d40984a571d0143924cd6f
4
- data.tar.gz: e88c336217ade2bad4b5952af5d178fb413fe9ef
3
+ metadata.gz: 4e1ad09e6adf2941686edf7a317cfabf117d6dc9
4
+ data.tar.gz: aace15466553dbf47588663c2d72fce3e2a300c9
5
5
  SHA512:
6
- metadata.gz: 428001bf5a64de77ece58679cf7250173f0c11f5fa956bc437abb23307354e93ae4620e7dfe1a7f098ce11c9b3683ac398c26a4bddf45ed47b6053a2796506de
7
- data.tar.gz: 0a131013da955c7b4c569aff0249b7de6e909f679cc53113ddc830549e52427fee054c119289f7e00e23cc7d1062fc98ba1247149696e912de0f4cc0b608e7d7
6
+ metadata.gz: 5ac4aebd582d8f25e19b74840b7c47f8959ded867413966e56df5b97dc54e2b3e6dc2762ddae777e4826038d5ebb35d61a0a9811dd847ac6617b3586b5d47c00
7
+ data.tar.gz: dcb9ef0b1a9cff3e869e65dab007953177e6e3fc4e4ada116228f05cb446655f83cca4945c4b512c9c608aba9bedf78de3a3168a970200cf248227183e32ac8e
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gem "hoe-ignore"
6
6
  gem "rdoc"
7
7
  gem "rake-compiler"
8
8
  gem "rack"
9
+ gem "test-unit", "~> 3.0"
9
10
 
10
11
  gem 'minitest', '~> 4.0'
11
12
 
@@ -14,4 +15,3 @@ gem "jruby-openssl", :platform => "jruby"
14
15
  platforms :rbx do
15
16
  gem 'rubysl', '~> 2.0'
16
17
  end
17
-
data/History.txt CHANGED
@@ -1,3 +1,36 @@
1
+ === 2.11.0 / 2015-01-20
2
+
3
+ * 9 bug fixes:
4
+ * Add mode as an additional bind option to unix sockets. Fixes #630
5
+ * Advertise HTTPS properly after a hot restart
6
+ * Don't write lowlevel_error_handler to state
7
+ * Fix phased restart with stuck requests
8
+ * Handle spaces in the path properly. Fixes #622
9
+ * Set a default REMOTE_ADDR to avoid using peeraddr on unix sockets. Fixes #583
10
+ * Skip device number checking on jruby. Fixes #586
11
+ * Update extconf.rb to compile correctly on OS X
12
+ * redirect io right after daemonizing so startup errors are shown. Fixes #359
13
+
14
+ * 6 minor features:
15
+ * Add a configuration option that prevents puma from queueing requests.
16
+ * Add reload_worker_directory
17
+ * Add the ability to pass environment variables to the init script (for Jungle).
18
+ * Add the proctitle tag to the worker. Fixes #633
19
+ * Infer a proctitle tag based on the directory
20
+ * Update lowlevel error message to be more meaningful.
21
+
22
+ * 10 PRs merged:
23
+ * Merge pull request #478 from rubencaro/master
24
+ * Merge pull request #610 from kwilczynski/master
25
+ * Merge pull request #611 from jasonl/better-lowlevel-message
26
+ * Merge pull request #616 from jc00ke/master
27
+ * Merge pull request #623 from raldred/patch-1
28
+ * Merge pull request #628 from rdpoor/master
29
+ * Merge pull request #634 from deepj/master
30
+ * Merge pull request #637 from raskhadafi/patch-1
31
+ * Merge pull request #639 from ebeigarts/fix-phased-restarts
32
+ * Merge pull request #640 from codehotter/issue-612-dependent-requests-deadlock
33
+
1
34
  === 2.10.2 / 2014-11-26
2
35
 
3
36
  * 1 bug fix:
@@ -2,8 +2,8 @@ require 'mkmf'
2
2
 
3
3
  dir_config("puma_http11")
4
4
 
5
- if %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')} and
6
- %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')}
7
-
5
+ if %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} and
6
+ %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
7
+
8
8
  create_makefile("puma/puma_http11")
9
9
  end
@@ -48,6 +48,13 @@ module Puma
48
48
  return rack_response(200, OK_STATUS)
49
49
  end
50
50
 
51
+ when /\/reload-worker-directory$/
52
+ if !@cli.reload_worker_directory
53
+ return rack_response(404, '{ "error": "reload_worker_directory not available" }')
54
+ else
55
+ return rack_response(200, OK_STATUS)
56
+ end
57
+
51
58
  when /\/stats$/
52
59
  return rack_response(200, @cli.stats)
53
60
  else
data/lib/puma/binder.rb CHANGED
@@ -98,7 +98,7 @@ module Puma
98
98
 
99
99
  @listeners << [str, io]
100
100
  when "unix"
101
- path = "#{uri.host}#{uri.path}"
101
+ path = "#{uri.host}#{uri.path}".gsub("%20", " ")
102
102
 
103
103
  if fd = @inherited_fds.delete(str)
104
104
  logger.log "* Inherited #{str}"
@@ -107,6 +107,7 @@ module Puma
107
107
  logger.log "* Listening on #{str}"
108
108
 
109
109
  umask = nil
110
+ mode = nil
110
111
 
111
112
  if uri.query
112
113
  params = Rack::Utils.parse_query uri.query
@@ -114,9 +115,13 @@ module Puma
114
115
  # Use Integer() to respect the 0 prefix as octal
115
116
  umask = Integer(u)
116
117
  end
118
+
119
+ if u = params['mode']
120
+ mode = Integer('0'+u)
121
+ end
117
122
  end
118
123
 
119
- io = add_unix_listener path, umask
124
+ io = add_unix_listener path, umask, mode
120
125
  end
121
126
 
122
127
  @listeners << [str, io]
@@ -247,13 +252,20 @@ module Puma
247
252
  def inherited_ssl_listener(fd, ctx)
248
253
  require 'puma/minissl'
249
254
  s = TCPServer.for_fd(fd)
250
- @ios << MiniSSL::Server.new(s, ctx)
255
+ ssl = MiniSSL::Server.new(s, ctx)
256
+
257
+ env = @proto_env.dup
258
+ env[HTTPS_KEY] = HTTPS
259
+ @envs[ssl] = env
260
+
261
+ @ios << ssl
262
+
251
263
  s
252
264
  end
253
265
 
254
266
  # Tell the server to listen on +path+ as a UNIX domain socket.
255
267
  #
256
- def add_unix_listener(path, umask=nil)
268
+ def add_unix_listener(path, umask=nil, mode=nil)
257
269
  @unix_paths << path
258
270
 
259
271
  # Let anyone connect by default
@@ -279,6 +291,14 @@ module Puma
279
291
  File.umask old_mask
280
292
  end
281
293
 
294
+ if mode
295
+ File.chmod mode, path
296
+ end
297
+
298
+ env = @proto_env.dup
299
+ env[REMOTE_ADDR] = "127.0.0.1"
300
+ @envs[s] = env
301
+
282
302
  s
283
303
  end
284
304
 
@@ -292,6 +312,10 @@ module Puma
292
312
  end
293
313
  @ios << s
294
314
 
315
+ env = @proto_env.dup
316
+ env[REMOTE_ADDR] = "127.0.0.1"
317
+ @envs[s] = env
318
+
295
319
  s
296
320
  end
297
321
 
data/lib/puma/cli.rb CHANGED
@@ -229,7 +229,7 @@ module Puma
229
229
 
230
230
  cfg = @config.dup
231
231
 
232
- [ :logger, :before_worker_shutdown, :before_worker_boot, :after_worker_boot, :on_restart ].each { |o| cfg.options.delete o }
232
+ [ :logger, :before_worker_shutdown, :before_worker_boot, :after_worker_boot, :on_restart, :lowlevel_error_handler ].each { |o| cfg.options.delete o }
233
233
 
234
234
  state["config"] = cfg
235
235
 
@@ -335,7 +335,7 @@ module Puma
335
335
  s_env = File.stat(dir)
336
336
  s_pwd = File.stat(Dir.pwd)
337
337
 
338
- if s_env.ino == s_pwd.ino and s_env.dev == s_pwd.dev
338
+ if s_env.ino == s_pwd.ino and (jruby? or s_env.dev == s_pwd.dev)
339
339
  @restart_dir = dir
340
340
  @options[:worker_directory] = dir
341
341
  end
@@ -491,7 +491,7 @@ module Puma
491
491
  set_rack_environment
492
492
 
493
493
  if clustered?
494
- @events = PidEvents.new STDOUT, STDERR
494
+ @events.formatter = Events::PidFormatter.new
495
495
  @options[:logger] = @events
496
496
 
497
497
  @runner = Cluster.new(self)
@@ -572,6 +572,10 @@ module Puma
572
572
  @runner.restart
573
573
  end
574
574
 
575
+ def reload_worker_directory
576
+ @runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
577
+ end
578
+
575
579
  def phased_restart
576
580
  unless @runner.respond_to?(:phased_restart) and @runner.phased_restart
577
581
  log "* phased-restart called but not available, restarting normally."
data/lib/puma/client.rb CHANGED
@@ -222,6 +222,14 @@ module Puma
222
222
  end
223
223
  end # IS_JRUBY
224
224
 
225
+ def finish
226
+ return true if @ready
227
+ until try_to_finish
228
+ IO.select([@to_io], nil, nil)
229
+ end
230
+ true
231
+ end
232
+
225
233
  def read_body
226
234
  # Read an odd sized chunk so we can read even sized ones
227
235
  # after this
data/lib/puma/cluster.rb CHANGED
@@ -43,12 +43,14 @@ module Puma
43
43
  end
44
44
 
45
45
  class Worker
46
- def initialize(idx, pid, phase)
46
+ def initialize(idx, pid, phase, options)
47
47
  @index = idx
48
48
  @pid = pid
49
49
  @phase = phase
50
50
  @stage = :started
51
51
  @signal = "TERM"
52
+ @options = options
53
+ @first_term_sent = nil
52
54
  @last_checkin = Time.now
53
55
  end
54
56
 
@@ -105,7 +107,7 @@ module Puma
105
107
 
106
108
  pid = fork { worker(idx, master) }
107
109
  @cli.debug "Spawned worker: #{pid}"
108
- @workers << Worker.new(idx, pid, @phase)
110
+ @workers << Worker.new(idx, pid, @phase, @options)
109
111
  @options[:after_worker_boot].each { |h| h.call }
110
112
  end
111
113
 
@@ -180,7 +182,10 @@ module Puma
180
182
  end
181
183
 
182
184
  def worker(index, master)
183
- $0 = "puma: cluster worker #{index}: #{master}"
185
+ title = "puma: cluster worker #{index}: #{master}"
186
+ title << " [#{@options[:tag]}]" if @options[:tag]
187
+ $0 = title
188
+
184
189
  Signal.trap "SIGINT", "IGNORE"
185
190
 
186
191
  @workers = []
@@ -267,6 +272,13 @@ module Puma
267
272
  wakeup!
268
273
  end
269
274
 
275
+ def reload_worker_directory
276
+ if dir = @options[:worker_directory]
277
+ log "+ Changing to #{dir}"
278
+ Dir.chdir dir
279
+ end
280
+ end
281
+
270
282
  def stats
271
283
  %Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{@workers.count{|w| w.booted?}} }!
272
284
  end
@@ -60,6 +60,14 @@ module Puma
60
60
  unless @options[:control_auth_token]
61
61
  setup_random_token
62
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
63
71
  end
64
72
 
65
73
  # Injects the Configuration object into the env
@@ -402,6 +410,23 @@ module Puma
402
410
  def worker_shutdown_timeout(timeout)
403
411
  @options[:worker_shutdown_timeout] = timeout
404
412
  end
413
+
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
405
430
  end
406
431
  end
407
432
  end
data/lib/puma/const.rb CHANGED
@@ -28,8 +28,8 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.10.2".freeze
32
- CODE_NAME = "Robots on Comets".freeze
31
+ PUMA_VERSION = VERSION = "2.11.0".freeze
32
+ CODE_NAME = "Intrepid Squirrel".freeze
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
35
35
 
@@ -7,7 +7,7 @@ require 'socket'
7
7
  module Puma
8
8
  class ControlCLI
9
9
 
10
- COMMANDS = %w{halt restart phased-restart start stats status stop}
10
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
11
11
 
12
12
  def is_windows?
13
13
  RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
@@ -201,6 +201,10 @@ module Puma
201
201
  puts "Stats not available via pid only"
202
202
  return
203
203
 
204
+ when "reload-worker-directory"
205
+ puts "reload-worker-directory not available via pid only"
206
+ return
207
+
204
208
  when "phased-restart"
205
209
  Process.kill "SIGUSR1", pid
206
210
 
data/lib/puma/events.rb CHANGED
@@ -8,12 +8,24 @@ module Puma
8
8
  # The methods available are the events that the Server fires.
9
9
  #
10
10
  class Events
11
+ class DefaultFormatter
12
+ def call(str)
13
+ str
14
+ end
15
+ end
16
+
17
+ class PidFormatter
18
+ def call(str)
19
+ "[#{$$}] #{str}"
20
+ end
21
+ end
11
22
 
12
23
  include Const
13
24
 
14
25
  # Create an Events object that prints to +stdout+ and +stderr+.
15
26
  #
16
27
  def initialize(stdout, stderr)
28
+ @formatter = DefaultFormatter.new
17
29
  @stdout = stdout
18
30
  @stderr = stderr
19
31
 
@@ -28,6 +40,7 @@ module Puma
28
40
  end
29
41
 
30
42
  attr_reader :stdout, :stderr
43
+ attr_accessor :formatter
31
44
 
32
45
  # Fire callbacks for the named hook
33
46
  #
@@ -52,11 +65,11 @@ module Puma
52
65
  # Write +str+ to +@stdout+
53
66
  #
54
67
  def log(str)
55
- @stdout.puts str
68
+ @stdout.puts format(str)
56
69
  end
57
70
 
58
71
  def write(str)
59
- @stdout.write str
72
+ @stdout.write format(str)
60
73
  end
61
74
 
62
75
  def debug(str)
@@ -66,10 +79,14 @@ module Puma
66
79
  # Write +str+ to +@stderr+
67
80
  #
68
81
  def error(str)
69
- @stderr.puts "ERROR: #{str}"
82
+ @stderr.puts format("ERROR: #{str}")
70
83
  exit 1
71
84
  end
72
85
 
86
+ def format(str)
87
+ formatter.call(str)
88
+ end
89
+
73
90
  # An HTTP parse error has occured.
74
91
  # +server+ is the Server object, +env+ the request, and +error+ a
75
92
  # parsing exception.
@@ -113,18 +130,4 @@ module Puma
113
130
  Events.new $stdout, $stderr
114
131
  end
115
132
  end
116
-
117
- class PidEvents < Events
118
- def log(str)
119
- super "[#{$$}] #{str}"
120
- end
121
-
122
- def write(str)
123
- super "[#{$$}] #{str}"
124
- end
125
-
126
- def error(str)
127
- super "[#{$$}] #{str}"
128
- end
129
- end
130
133
  end
data/lib/puma/server.rb CHANGED
@@ -74,6 +74,7 @@ module Puma
74
74
  @leak_stack_on_error = true
75
75
 
76
76
  @options = options
77
+ @queue_requests = options[:queue_requests].nil? ? true : options[:queue_requests]
77
78
 
78
79
  ENV['RACK_ENV'] ||= "development"
79
80
 
@@ -235,13 +236,20 @@ module Puma
235
236
  return run_lopez_mode(background)
236
237
  end
237
238
 
239
+ queue_requests = @queue_requests
240
+
238
241
  @thread_pool = ThreadPool.new(@min_threads,
239
242
  @max_threads,
240
243
  IOBuffer) do |client, buffer|
241
244
  process_now = false
242
245
 
243
246
  begin
244
- process_now = client.eagerly_finish
247
+ if queue_requests
248
+ process_now = client.eagerly_finish
249
+ else
250
+ client.finish
251
+ process_now = true
252
+ end
245
253
  rescue HttpParserError => e
246
254
  client.write_400
247
255
  client.close
@@ -261,9 +269,10 @@ module Puma
261
269
 
262
270
  @thread_pool.clean_thread_locals = @options[:clean_thread_locals]
263
271
 
264
- @reactor = Reactor.new self, @thread_pool
265
-
266
- @reactor.run_in_thread
272
+ if queue_requests
273
+ @reactor = Reactor.new self, @thread_pool
274
+ @reactor.run_in_thread
275
+ end
267
276
 
268
277
  if @auto_trim_time
269
278
  @thread_pool.auto_trim!(@auto_trim_time)
@@ -284,6 +293,7 @@ module Puma
284
293
  check = @check
285
294
  sockets = [check] + @binder.ios
286
295
  pool = @thread_pool
296
+ queue_requests = @queue_requests
287
297
 
288
298
  while @status == :run
289
299
  begin
@@ -296,6 +306,7 @@ module Puma
296
306
  if io = sock.accept_nonblock
297
307
  client = Client.new io, @binder.env(sock)
298
308
  pool << client
309
+ pool.wait_until_not_full unless queue_requests
299
310
  end
300
311
  rescue SystemCallError
301
312
  end
@@ -312,9 +323,10 @@ module Puma
312
323
  @events.fire :state, @status
313
324
 
314
325
  graceful_shutdown if @status == :stop || @status == :restart
315
- @reactor.clear! if @status == :restart
316
-
317
- @reactor.shutdown
326
+ if queue_requests
327
+ @reactor.clear! if @status == :restart
328
+ @reactor.shutdown
329
+ end
318
330
  rescue Exception => e
319
331
  STDERR.puts "Exception handling servers: #{e.message} (#{e.class})"
320
332
  STDERR.puts e.backtrace
@@ -367,6 +379,7 @@ module Puma
367
379
  close_socket = false
368
380
  return
369
381
  when true
382
+ return unless @queue_requests
370
383
  buffer.reset
371
384
 
372
385
  unless client.reset(@status == :run)
@@ -443,12 +456,14 @@ module Puma
443
456
  # intermediary acting on behalf of the actual source client."
444
457
  #
445
458
 
446
- addr = client.peeraddr.last
459
+ unless env.key?(REMOTE_ADDR)
460
+ addr = client.peeraddr.last
447
461
 
448
- # Set unix socket addrs to localhost
449
- addr = "127.0.0.1" if addr.empty?
462
+ # Set unix socket addrs to localhost
463
+ addr = "127.0.0.1" if addr.empty?
450
464
 
451
- env[REMOTE_ADDR] = addr
465
+ env[REMOTE_ADDR] = addr
466
+ end
452
467
  end
453
468
 
454
469
  def default_server_port(env)
@@ -716,7 +731,7 @@ module Puma
716
731
  if @leak_stack_on_error
717
732
  [500, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{e.backtrace.join("\n")}"]]
718
733
  else
719
- [500, {}, ["A really lowlevel plumbing error occured. Please contact your local Maytag(tm) repair person.\n"]]
734
+ [500, {}, ["An unhandled lowlevel error occured. The application logs may have details.\n"]]
720
735
  end
721
736
  end
722
737
 
data/lib/puma/single.rb CHANGED
@@ -73,6 +73,7 @@ module Puma
73
73
  if daemon?
74
74
  log "* Daemonizing..."
75
75
  Process.daemon(true)
76
+ redirect_io
76
77
  end
77
78
 
78
79
  load_and_bind
@@ -84,12 +85,11 @@ module Puma
84
85
 
85
86
  @server = server = start_server
86
87
 
87
- unless @options[:daemon]
88
+ unless daemon?
88
89
  log "Use Ctrl-C to stop"
90
+ redirect_io
89
91
  end
90
92
 
91
- redirect_io
92
-
93
93
  @cli.events.fire_on_booted!
94
94
 
95
95
  begin
@@ -12,7 +12,8 @@ module Puma
12
12
  # thread.
13
13
  #
14
14
  def initialize(min, max, *extra, &block)
15
- @cond = ConditionVariable.new
15
+ @not_empty = ConditionVariable.new
16
+ @not_full = ConditionVariable.new
16
17
  @mutex = Mutex.new
17
18
 
18
19
  @todo = []
@@ -60,7 +61,8 @@ module Puma
60
61
  todo = @todo
61
62
  block = @block
62
63
  mutex = @mutex
63
- cond = @cond
64
+ not_empty = @not_empty
65
+ not_full = @not_full
64
66
 
65
67
  extra = @extra.map { |i| i.new }
66
68
 
@@ -83,7 +85,8 @@ module Puma
83
85
  end
84
86
 
85
87
  @waiting += 1
86
- cond.wait mutex
88
+ not_full.signal
89
+ not_empty.wait mutex
87
90
  @waiting -= 1
88
91
  end
89
92
 
@@ -127,7 +130,15 @@ module Puma
127
130
  spawn_thread
128
131
  end
129
132
 
130
- @cond.signal
133
+ @not_empty.signal
134
+ end
135
+ end
136
+
137
+ def wait_until_not_full
138
+ @mutex.synchronize do
139
+ until @todo.size - @waiting < @max - @spawned or @shutdown
140
+ @not_full.wait @mutex
141
+ end
131
142
  end
132
143
  end
133
144
 
@@ -139,7 +150,7 @@ module Puma
139
150
  @mutex.synchronize do
140
151
  if (force or @waiting > 0) and @spawned - @trim_requested > @min
141
152
  @trim_requested += 1
142
- @cond.signal
153
+ @not_empty.signal
143
154
  end
144
155
  end
145
156
  end
@@ -178,7 +189,8 @@ module Puma
178
189
  def shutdown
179
190
  @mutex.synchronize do
180
191
  @shutdown = true
181
- @cond.broadcast
192
+ @not_empty.broadcast
193
+ @not_full.broadcast
182
194
 
183
195
  @auto_trim.stop if @auto_trim
184
196
  end
@@ -59,8 +59,3 @@ module Rack
59
59
  end
60
60
  end
61
61
 
62
- # This is to trick newrelic into enabling the agent automatically.
63
- module Mongrel
64
- class HttpServer
65
- end
66
- end
@@ -102,6 +102,47 @@ class TestIntegration < Test::Unit::TestCase
102
102
  assert_kind_of Thread, t.join(1), "server didn't stop"
103
103
  end
104
104
 
105
+ def notest_phased_restart_via_pumactl
106
+ if defined?(JRUBY_VERSION) || RbConfig::CONFIG["host_os"] =~ /mingw|mswin/
107
+ assert true
108
+ return
109
+ end
110
+
111
+ cli = Puma::CLI.new %W!-q -S #{@state_path} -b unix://#{@bind_path} --control unix://#{@control_path} -w 2 test/hello-stuck.ru!, @events
112
+ cli.options[:worker_shutdown_timeout] = 1
113
+
114
+ t = Thread.new do
115
+ cli.run
116
+ end
117
+
118
+ wait_booted
119
+
120
+ # Make both workers stuck
121
+ s1 = UNIXSocket.new @bind_path
122
+ s1 << "GET / HTTP/1.0\r\n\r\n"
123
+ s2 = UNIXSocket.new @bind_path
124
+ s2 << "GET / HTTP/1.0\r\n\r\n"
125
+
126
+ sout = StringIO.new
127
+
128
+ # Phased restart
129
+ ccli = Puma::ControlCLI.new %W!-S #{@state_path} phased-restart!, sout
130
+ ccli.run
131
+ sleep 20
132
+ @events.stdout.rewind
133
+ log = @events.stdout.readlines.join("")
134
+ assert_match(/TERM sent/, log)
135
+ assert_match(/KILL sent/, log)
136
+ assert_match(/Worker 0 \(pid: \d+\) booted, phase: 1/, log)
137
+ assert_match(/Worker 1 \(pid: \d+\) booted, phase: 1/, log)
138
+
139
+ # Stop
140
+ ccli = Puma::ControlCLI.new %W!-S #{@state_path} stop!, sout
141
+ ccli.run
142
+
143
+ assert_kind_of Thread, t.join(5), "server didn't stop"
144
+ end
145
+
105
146
  def notest_restart_closes_keepalive_sockets
106
147
  server("-q test/hello.ru")
107
148
 
@@ -47,7 +47,8 @@ do_start() {
47
47
  if [ "$log_file" = "" ]; then
48
48
  log_file="$dir/log/puma.log"
49
49
  fi
50
- do_start_one $dir $user $config_file $log_file
50
+ environment=`echo $i | cut -d , -f 5`
51
+ do_start_one $dir $user $config_file $log_file $environment
51
52
  done
52
53
  }
53
54
 
@@ -57,12 +58,12 @@ do_start_one() {
57
58
  PID=`cat $PIDFILE`
58
59
  # If the puma isn't running, run it, otherwise restart it.
59
60
  if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
60
- do_start_one_do $1 $2 $3 $4
61
+ do_start_one_do $1 $2 $3 $4 $5
61
62
  else
62
63
  do_restart_one $1
63
64
  fi
64
65
  else
65
- do_start_one_do $1 $2 $3 $4
66
+ do_start_one_do $1 $2 $3 $4 $5
66
67
  fi
67
68
  }
68
69
 
@@ -70,6 +71,14 @@ do_start_one_do() {
70
71
  log_daemon_msg "--> Woke up puma $1"
71
72
  log_daemon_msg "user $2"
72
73
  log_daemon_msg "log to $4"
74
+
75
+ if [ ! -z "$5" ]; then
76
+ for e in $(echo "$5" | tr ';' '\n'); do
77
+ log_daemon_msg "environment $e"
78
+ v=${e%%\=*} ; eval "$e" ; export $v
79
+ done
80
+ fi
81
+
73
82
  start-stop-daemon --verbose --start --chdir $1 --chuid $2 --background --exec $RUNPUMA -- $1 $3 $4
74
83
  }
75
84
 
@@ -140,7 +149,8 @@ do_restart_one() {
140
149
  if [ "$log_file" = "" ]; then
141
150
  log_file="$dir/log/puma.log"
142
151
  fi
143
- do_start_one $dir $user $config_file $log_file
152
+ environment=`echo $i | cut -d , -f 5`
153
+ do_start_one $dir $user $config_file $log_file $environment
144
154
  fi
145
155
  return 0
146
156
  }
@@ -209,6 +219,11 @@ do_add() {
209
219
  str="$str,$4"
210
220
  fi
211
221
 
222
+ # Environment variables
223
+ if [ "$5" != "" ]; then
224
+ str="$str,$5"
225
+ fi
226
+
212
227
  # Add it to the jungle
213
228
  echo $str >> $CONFIG
214
229
  log_daemon_msg "Added a Puma to the jungle: $str. You still have to start it though."
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.2
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-27 00:00:00.000000000 Z
11
+ date: 2015-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '3.12'
67
+ version: '3.13'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '3.12'
74
+ version: '3.13'
75
75
  description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
76
76
  for Ruby/Rack applications. Puma is intended for use in both development and production
77
77
  environments. In order to get the best throughput, it is highly recommended that