puma 2.1.1-java → 2.2.0-java

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.

@@ -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#L138) to see all available options.
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 mechanism:
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|
@@ -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
- # Bind before redirecting IO so binding errors show up on stdout/stderr
465
- @binder.parse @options[:binds], self
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
- elsif daemon?
505
- Process.daemon(true)
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
- server = Puma::Server.new @config.app, @events
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
- @binder.parse @options[:binds], self
737
+ if @options[:preload_app]
738
+ log "* Preloading application"
739
+ load_and_bind
740
+ else
741
+ log "* Phased restart available"
719
742
 
720
- unless @config.app_configured?
721
- error "No application configured, nothing to run"
722
- exit 1
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
- Signal.trap "SIGUSR1" do
764
- phased_restart = true
765
- wakeup!
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
@@ -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
@@ -28,7 +28,7 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.1.1".freeze
31
+ PUMA_VERSION = VERSION = "2.2.0".freeze
32
32
 
33
33
  FAST_TRACK_KA_TIMEOUT = 0.2
34
34
 
@@ -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
- [500, {}, ["Puma caught this error: #{e}\n#{e.backtrace.join("\n")}"]]
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.
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "2.1.1"
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-06-20"
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"]
@@ -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
@@ -2,14 +2,14 @@
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.1.1
5
+ version: 2.2.0
6
6
  platform: java
7
7
  authors:
8
8
  - Evan Phoenix
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-20 00:00:00.000000000 Z
12
+ date: 2013-07-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack