puma 2.1.1 → 2.2.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.
- data/History.txt +11 -0
- data/README.md +2 -2
- data/Rakefile +44 -0
- data/lib/puma/cli.rb +63 -30
- data/lib/puma/configuration.rb +8 -0
- data/lib/puma/const.rb +1 -1
- data/lib/puma/server.rb +9 -3
- data/puma.gemspec +2 -2
- data/test/test_puma_server.rb +17 -0
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 2.2.0 / 2013-07-01
|
2
|
+
|
3
|
+
* 1 major feature:
|
4
|
+
|
5
|
+
* Add ability to preload rack app
|
6
|
+
|
7
|
+
* 2 minor bugfixes:
|
8
|
+
|
9
|
+
* Don't leak info when not in development. Fixes #256
|
10
|
+
* Load the app, then bind the ports
|
11
|
+
|
1
12
|
=== 2.1.1 / 2013-06-20
|
2
13
|
|
3
14
|
* 2 minor bug fixes:
|
data/README.md
CHANGED
@@ -134,13 +134,13 @@ or
|
|
134
134
|
|
135
135
|
$ puma -C /path/to/config
|
136
136
|
|
137
|
-
Take the following [sample configuration](https://github.com/puma/puma/blob/master/examples/config.rb) as inspiration or check out [configuration.rb](https://github.com/puma/puma/blob/master/lib/puma/configuration.rb
|
137
|
+
Take the following [sample configuration](https://github.com/puma/puma/blob/master/examples/config.rb) as inspiration or check out [configuration.rb](https://github.com/puma/puma/blob/master/lib/puma/configuration.rb) to see all available options.
|
138
138
|
|
139
139
|
## Restart
|
140
140
|
|
141
141
|
Puma includes the ability to restart itself, allowing for new versions to be easily upgraded to. When available (MRI, Rubinius, JRuby), puma performs a "hot restart". This is the same functionality available in *unicorn* and *nginx* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place.
|
142
142
|
|
143
|
-
To perform a restart, there are 2 builtin
|
143
|
+
To perform a restart, there are 2 builtin mechanisms:
|
144
144
|
|
145
145
|
* Send the puma process the `SIGUSR2` signal
|
146
146
|
* Use the status server and issue `/restart`
|
data/Rakefile
CHANGED
@@ -28,6 +28,50 @@ end
|
|
28
28
|
# hoe/test's .gemtest touch file thingy for now
|
29
29
|
HOE.spec.files -= [".gemtest"]
|
30
30
|
|
31
|
+
include Hoe::Git
|
32
|
+
|
33
|
+
desc "Print the current changelog."
|
34
|
+
task "changelog" do
|
35
|
+
tag = ENV["FROM"] || git_tags.last
|
36
|
+
range = [tag, "HEAD"].compact.join ".."
|
37
|
+
cmd = "git log #{range} '--format=tformat:%B|||%aN|||%aE|||'"
|
38
|
+
now = Time.new.strftime "%Y-%m-%d"
|
39
|
+
|
40
|
+
changes = `#{cmd}`.split(/\|\|\|/).each_slice(3).map { |msg, author, email|
|
41
|
+
msg.split(/\n/).reject { |s| s.empty? }.first
|
42
|
+
}.flatten.compact
|
43
|
+
|
44
|
+
$changes = Hash.new { |h,k| h[k] = [] }
|
45
|
+
|
46
|
+
codes = {
|
47
|
+
"!" => :major,
|
48
|
+
"+" => :minor,
|
49
|
+
"*" => :minor,
|
50
|
+
"-" => :bug,
|
51
|
+
"?" => :unknown,
|
52
|
+
}
|
53
|
+
|
54
|
+
codes_re = Regexp.escape codes.keys.join
|
55
|
+
|
56
|
+
changes.each do |change|
|
57
|
+
if change =~ /^\s*([#{codes_re}])\s*(.*)/ then
|
58
|
+
code, line = codes[$1], $2
|
59
|
+
else
|
60
|
+
code, line = codes["?"], change.chomp
|
61
|
+
end
|
62
|
+
|
63
|
+
$changes[code] << line
|
64
|
+
end
|
65
|
+
|
66
|
+
puts "=== #{ENV['VERSION'] || 'NEXT'} / #{now}"
|
67
|
+
puts
|
68
|
+
changelog_section :major
|
69
|
+
changelog_section :minor
|
70
|
+
changelog_section :bug
|
71
|
+
changelog_section :unknown
|
72
|
+
puts
|
73
|
+
end
|
74
|
+
|
31
75
|
# puma.gemspec
|
32
76
|
|
33
77
|
file "#{HOE.spec.name}.gemspec" => ['Rakefile', "lib/puma/const.rb"] do |t|
|
data/lib/puma/cli.rb
CHANGED
@@ -39,6 +39,8 @@ module Puma
|
|
39
39
|
@restart = false
|
40
40
|
@phased_state = :idle
|
41
41
|
|
42
|
+
@app = nil
|
43
|
+
|
42
44
|
ENV['NEWRELIC_DISPATCHER'] ||= "puma"
|
43
45
|
|
44
46
|
setup_options
|
@@ -302,6 +304,10 @@ module Puma
|
|
302
304
|
ENV['RACK_ENV'] = env
|
303
305
|
end
|
304
306
|
|
307
|
+
def development?
|
308
|
+
@options[:environment] == "development"
|
309
|
+
end
|
310
|
+
|
305
311
|
def delete_pidfile
|
306
312
|
if path = @options[:pidfile]
|
307
313
|
File.unlink path
|
@@ -454,6 +460,23 @@ module Puma
|
|
454
460
|
@status = status
|
455
461
|
end
|
456
462
|
|
463
|
+
def load_and_bind
|
464
|
+
unless @config.app_configured?
|
465
|
+
error "No application configured, nothing to run"
|
466
|
+
exit 1
|
467
|
+
end
|
468
|
+
|
469
|
+
# Load the app before we daemonize.
|
470
|
+
begin
|
471
|
+
@app = @config.app
|
472
|
+
rescue Exception => e
|
473
|
+
log "! Unable to load application"
|
474
|
+
raise e
|
475
|
+
end
|
476
|
+
|
477
|
+
@binder.parse @options[:binds], self
|
478
|
+
end
|
479
|
+
|
457
480
|
def run_single
|
458
481
|
already_daemon = false
|
459
482
|
|
@@ -461,8 +484,8 @@ module Puma
|
|
461
484
|
require 'puma/jruby_restart'
|
462
485
|
|
463
486
|
if JRubyRestart.daemon?
|
464
|
-
#
|
465
|
-
|
487
|
+
# load and bind before redirecting IO so errors show up on stdout/stderr
|
488
|
+
load_and_bind
|
466
489
|
end
|
467
490
|
|
468
491
|
already_daemon = JRubyRestart.daemon_init
|
@@ -470,23 +493,6 @@ module Puma
|
|
470
493
|
|
471
494
|
output_header
|
472
495
|
|
473
|
-
if !jruby_daemon?
|
474
|
-
@binder.parse @options[:binds], self
|
475
|
-
end
|
476
|
-
|
477
|
-
unless @config.app_configured?
|
478
|
-
error "No application configured, nothing to run"
|
479
|
-
exit 1
|
480
|
-
end
|
481
|
-
|
482
|
-
# Load the app before we daemonize.
|
483
|
-
begin
|
484
|
-
app = @config.app
|
485
|
-
rescue Exception => e
|
486
|
-
log "! Unable to load application"
|
487
|
-
raise e
|
488
|
-
end
|
489
|
-
|
490
496
|
if jruby_daemon?
|
491
497
|
unless already_daemon
|
492
498
|
require 'puma/jruby_restart'
|
@@ -501,17 +507,22 @@ module Puma
|
|
501
507
|
pid = JRubyRestart.daemon_start(@restart_dir, @restart_argv)
|
502
508
|
sleep
|
503
509
|
end
|
504
|
-
|
505
|
-
|
510
|
+
else
|
511
|
+
load_and_bind
|
512
|
+
Process.daemon(true) if daemon?
|
506
513
|
end
|
507
514
|
|
508
515
|
write_state
|
509
516
|
|
510
|
-
server = Puma::Server.new app, @events
|
517
|
+
server = Puma::Server.new @app, @events
|
511
518
|
server.binder = @binder
|
512
519
|
server.min_threads = @options[:min_threads]
|
513
520
|
server.max_threads = @options[:max_threads]
|
514
521
|
|
522
|
+
unless development?
|
523
|
+
server.leak_stack_on_error = false
|
524
|
+
end
|
525
|
+
|
515
526
|
@server = server
|
516
527
|
|
517
528
|
if str = @options[:control_url]
|
@@ -592,11 +603,19 @@ module Puma
|
|
592
603
|
min_t = @options[:min_threads]
|
593
604
|
max_t = @options[:max_threads]
|
594
605
|
|
595
|
-
|
606
|
+
# If preload is used, then @app is set to the preloaded
|
607
|
+
# application. Otherwise load it now via the config.
|
608
|
+
app = @app || @config.app
|
609
|
+
|
610
|
+
server = Puma::Server.new app, @events
|
596
611
|
server.min_threads = min_t
|
597
612
|
server.max_threads = max_t
|
598
613
|
server.inherit_binder @binder
|
599
614
|
|
615
|
+
unless development?
|
616
|
+
server.leak_stack_on_error = false
|
617
|
+
end
|
618
|
+
|
600
619
|
Signal.trap "SIGTERM" do
|
601
620
|
server.stop
|
602
621
|
end
|
@@ -715,11 +734,18 @@ module Puma
|
|
715
734
|
log "* Min threads: #{@options[:min_threads]}, max threads: #{@options[:max_threads]}"
|
716
735
|
log "* Environment: #{ENV['RACK_ENV']}"
|
717
736
|
|
718
|
-
|
737
|
+
if @options[:preload_app]
|
738
|
+
log "* Preloading application"
|
739
|
+
load_and_bind
|
740
|
+
else
|
741
|
+
log "* Phased restart available"
|
719
742
|
|
720
|
-
|
721
|
-
|
722
|
-
|
743
|
+
unless @config.app_configured?
|
744
|
+
error "No application configured, nothing to run"
|
745
|
+
exit 1
|
746
|
+
end
|
747
|
+
|
748
|
+
@binder.parse @options[:binds], self
|
723
749
|
end
|
724
750
|
|
725
751
|
read, @wakeup = Puma::Util.pipe
|
@@ -760,9 +786,16 @@ module Puma
|
|
760
786
|
phased_restart = false
|
761
787
|
|
762
788
|
begin
|
763
|
-
|
764
|
-
|
765
|
-
|
789
|
+
if @options[:preload_app]
|
790
|
+
Signal.trap "SIGUSR1" do
|
791
|
+
log "App preloaded, phased restart unavailable"
|
792
|
+
end
|
793
|
+
else
|
794
|
+
Signal.trap "SIGUSR1" do
|
795
|
+
phased_restart = true
|
796
|
+
@wakeup << "!"
|
797
|
+
wakeup!
|
798
|
+
end
|
766
799
|
end
|
767
800
|
rescue Exception
|
768
801
|
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -287,6 +287,14 @@ module Puma
|
|
287
287
|
@options[:directory] = dir.to_s
|
288
288
|
@options[:worker_directory] = dir.to_s
|
289
289
|
end
|
290
|
+
|
291
|
+
# *Cluster mode only* Preload the application before starting
|
292
|
+
# the workers and setting up the listen ports. This conflicts
|
293
|
+
# with using the phased restart feature, you can't use both.
|
294
|
+
#
|
295
|
+
def preload_app!(answer=true)
|
296
|
+
@options[:preload_app] = answer
|
297
|
+
end
|
290
298
|
end
|
291
299
|
end
|
292
300
|
end
|
data/lib/puma/const.rb
CHANGED
data/lib/puma/server.rb
CHANGED
@@ -68,10 +68,12 @@ module Puma
|
|
68
68
|
|
69
69
|
@first_data_timeout = FIRST_DATA_TIMEOUT
|
70
70
|
|
71
|
+
@leak_stack_on_error = true
|
72
|
+
|
71
73
|
ENV['RACK_ENV'] ||= "development"
|
72
74
|
end
|
73
75
|
|
74
|
-
attr_accessor :binder
|
76
|
+
attr_accessor :binder, :leak_stack_on_error
|
75
77
|
|
76
78
|
forward :add_tcp_listener, :@binder
|
77
79
|
forward :add_ssl_listener, :@binder
|
@@ -379,7 +381,7 @@ module Puma
|
|
379
381
|
|
380
382
|
return :async
|
381
383
|
end
|
382
|
-
rescue => e
|
384
|
+
rescue StandardError => e
|
383
385
|
@events.unknown_error self, e, "Rack app"
|
384
386
|
|
385
387
|
status, headers, res_body = lowlevel_error(e)
|
@@ -571,7 +573,11 @@ module Puma
|
|
571
573
|
# A fallback rack response if +@app+ raises as exception.
|
572
574
|
#
|
573
575
|
def lowlevel_error(e)
|
574
|
-
|
576
|
+
if @leak_stack_on_error
|
577
|
+
[500, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{e.backtrace.join("\n")}"]]
|
578
|
+
else
|
579
|
+
[500, {}, ["A really lowlevel plumbing error occured. Please contact your local Maytag(tm) repair man.\n"]]
|
580
|
+
end
|
575
581
|
end
|
576
582
|
|
577
583
|
# Wait for all outstanding requests to finish.
|
data/puma.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "puma"
|
5
|
-
s.version = "2.
|
5
|
+
s.version = "2.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Evan Phoenix"]
|
9
|
-
s.date = "2013-
|
9
|
+
s.date = "2013-07-02"
|
10
10
|
s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like Rubinius or JRuby."
|
11
11
|
s.email = ["evan@phx.io"]
|
12
12
|
s.executables = ["puma", "pumactl"]
|
data/test/test_puma_server.rb
CHANGED
@@ -204,4 +204,21 @@ class TestPumaServer < Test::Unit::TestCase
|
|
204
204
|
|
205
205
|
assert_equal "HTTP/1.0 200 OK\r\n\r\n", data
|
206
206
|
end
|
207
|
+
|
208
|
+
def test_doesnt_print_backtrace_in_production
|
209
|
+
@events = Puma::Events.strings
|
210
|
+
@server = Puma::Server.new @app, @events
|
211
|
+
|
212
|
+
@server.app = proc { |e| raise "don't leak me bro" }
|
213
|
+
@server.leak_stack_on_error = false
|
214
|
+
@server.add_tcp_listener @host, @port
|
215
|
+
@server.run
|
216
|
+
|
217
|
+
sock = TCPSocket.new @host, @port
|
218
|
+
sock << "GET / HTTP/1.0\r\n\r\n"
|
219
|
+
|
220
|
+
data = sock.read
|
221
|
+
|
222
|
+
assert_not_match(/don't leak me bro/, data)
|
223
|
+
end
|
207
224
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|