puma 5.0.4 → 5.6.4

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.

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +322 -48
  3. data/LICENSE +0 -0
  4. data/README.md +95 -24
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +57 -20
  7. data/docs/compile_options.md +21 -0
  8. data/docs/deployment.md +53 -67
  9. data/docs/fork_worker.md +2 -0
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +0 -0
  14. data/docs/jungle/rc.d/README.md +1 -1
  15. data/docs/jungle/rc.d/puma.conf +0 -0
  16. data/docs/kubernetes.md +66 -0
  17. data/docs/nginx.md +0 -0
  18. data/docs/plugins.md +15 -15
  19. data/docs/rails_dev_mode.md +28 -0
  20. data/docs/restart.md +7 -7
  21. data/docs/signals.md +11 -10
  22. data/docs/stats.md +142 -0
  23. data/docs/systemd.md +85 -66
  24. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  25. data/ext/puma_http11/ext_help.h +0 -0
  26. data/ext/puma_http11/extconf.rb +42 -6
  27. data/ext/puma_http11/http11_parser.c +68 -57
  28. data/ext/puma_http11/http11_parser.h +1 -1
  29. data/ext/puma_http11/http11_parser.java.rl +1 -1
  30. data/ext/puma_http11/http11_parser.rl +1 -1
  31. data/ext/puma_http11/http11_parser_common.rl +1 -1
  32. data/ext/puma_http11/mini_ssl.c +226 -88
  33. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  34. data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
  35. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +51 -51
  36. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
  37. data/ext/puma_http11/puma_http11.c +9 -3
  38. data/lib/puma/app/status.rb +4 -7
  39. data/lib/puma/binder.rb +138 -49
  40. data/lib/puma/cli.rb +18 -4
  41. data/lib/puma/client.rb +113 -31
  42. data/lib/puma/cluster/worker.rb +22 -19
  43. data/lib/puma/cluster/worker_handle.rb +13 -2
  44. data/lib/puma/cluster.rb +75 -33
  45. data/lib/puma/commonlogger.rb +0 -0
  46. data/lib/puma/configuration.rb +21 -2
  47. data/lib/puma/const.rb +17 -8
  48. data/lib/puma/control_cli.rb +76 -71
  49. data/lib/puma/detect.rb +19 -9
  50. data/lib/puma/dsl.rb +225 -31
  51. data/lib/puma/error_logger.rb +12 -5
  52. data/lib/puma/events.rb +18 -3
  53. data/lib/puma/io_buffer.rb +0 -0
  54. data/lib/puma/jruby_restart.rb +0 -0
  55. data/lib/puma/json_serialization.rb +96 -0
  56. data/lib/puma/launcher.rb +56 -7
  57. data/lib/puma/minissl/context_builder.rb +14 -6
  58. data/lib/puma/minissl.rb +72 -40
  59. data/lib/puma/null_io.rb +12 -0
  60. data/lib/puma/plugin/tmp_restart.rb +0 -0
  61. data/lib/puma/plugin.rb +2 -2
  62. data/lib/puma/queue_close.rb +7 -7
  63. data/lib/puma/rack/builder.rb +1 -1
  64. data/lib/puma/rack/urlmap.rb +0 -0
  65. data/lib/puma/rack_default.rb +0 -0
  66. data/lib/puma/reactor.rb +19 -12
  67. data/lib/puma/request.rb +55 -21
  68. data/lib/puma/runner.rb +39 -13
  69. data/lib/puma/server.rb +78 -142
  70. data/lib/puma/single.rb +0 -0
  71. data/lib/puma/state_file.rb +45 -9
  72. data/lib/puma/systemd.rb +46 -0
  73. data/lib/puma/thread_pool.rb +11 -8
  74. data/lib/puma/util.rb +8 -1
  75. data/lib/puma.rb +36 -10
  76. data/lib/rack/handler/puma.rb +1 -0
  77. data/tools/Dockerfile +1 -1
  78. data/tools/trickletest.rb +0 -0
  79. metadata +15 -9
@@ -1,27 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module Puma
4
+
5
+ # Puma::Launcher uses StateFile to write a yaml file for use with Puma::ControlCLI.
6
+ #
7
+ # In previous versions of Puma, YAML was used to read/write the state file.
8
+ # Since Puma is similar to Bundler/RubyGems in that it may load before one's app
9
+ # does, minimizing the dependencies that may be shared with the app is desired.
10
+ #
11
+ # At present, it only works with numeric and string values. It is still a valid
12
+ # yaml file, and the CI tests parse it with Psych.
13
+ #
6
14
  class StateFile
15
+
16
+ ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
17
+
18
+ # @deprecated 6.0.0
19
+ FIELDS = ALLOWED_FIELDS
20
+
7
21
  def initialize
8
22
  @options = {}
9
23
  end
10
24
 
11
25
  def save(path, permission = nil)
12
- File.open(path, "w") do |file|
13
- file.chmod(permission) if permission
14
- file.write(YAML.dump(@options))
26
+ contents = "---\n".dup
27
+ @options.each do |k,v|
28
+ next unless ALLOWED_FIELDS.include? k
29
+ case v
30
+ when Numeric
31
+ contents << "#{k}: #{v}\n"
32
+ when String
33
+ next if v.strip.empty?
34
+ contents << (k == 'running_from' || v.to_s.include?(' ') ?
35
+ "#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
36
+ end
37
+ end
38
+ if permission
39
+ File.write path, contents, mode: 'wb:UTF-8'
40
+ else
41
+ File.write path, contents, mode: 'wb:UTF-8', perm: permission
15
42
  end
16
43
  end
17
44
 
18
45
  def load(path)
19
- @options = YAML.load File.read(path)
46
+ File.read(path).lines.each do |line|
47
+ next if line.start_with? '#'
48
+ k,v = line.split ':', 2
49
+ next unless v && ALLOWED_FIELDS.include?(k)
50
+ v = v.strip
51
+ @options[k] =
52
+ case v
53
+ when /\A\d+\z/ then v.to_i
54
+ when /\A\d+\.\d+\z/ then v.to_f
55
+ else v.gsub(/\A"|"\z/, '')
56
+ end
57
+ end
20
58
  end
21
59
 
22
- FIELDS = %w!control_url control_auth_token pid running_from!
23
-
24
- FIELDS.each do |f|
60
+ ALLOWED_FIELDS.each do |f|
25
61
  define_method f do
26
62
  @options[f]
27
63
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sd_notify'
4
+
5
+ module Puma
6
+ class Systemd
7
+ def initialize(events)
8
+ @events = events
9
+ end
10
+
11
+ def hook_events
12
+ @events.on_booted { SdNotify.ready }
13
+ @events.on_stopped { SdNotify.stopping }
14
+ @events.on_restart { SdNotify.reloading }
15
+ end
16
+
17
+ def start_watchdog
18
+ return unless SdNotify.watchdog?
19
+
20
+ ping_f = watchdog_sleep_time
21
+
22
+ log "Pinging systemd watchdog every #{ping_f.round(1)} sec"
23
+ Thread.new do
24
+ loop do
25
+ sleep ping_f
26
+ SdNotify.watchdog
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def watchdog_sleep_time
34
+ usec = Integer(ENV["WATCHDOG_USEC"])
35
+
36
+ sec_f = usec / 1_000_000.0
37
+ # "It is recommended that a daemon sends a keep-alive notification message
38
+ # to the service manager every half of the time returned here."
39
+ sec_f / 2
40
+ end
41
+
42
+ def log(str)
43
+ @events.log str
44
+ end
45
+ end
46
+ end
@@ -13,7 +13,7 @@ module Puma
13
13
  # a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in a `@todo` array.
14
14
  #
15
15
  # Each thread in the pool has an internal loop where it pulls a request from the `@todo` array
16
- # and proceses it.
16
+ # and processes it.
17
17
  class ThreadPool
18
18
  class ForceShutdown < RuntimeError
19
19
  end
@@ -29,7 +29,7 @@ module Puma
29
29
  # The block passed is the work that will be performed in each
30
30
  # thread.
31
31
  #
32
- def initialize(min, max, *extra, &block)
32
+ def initialize(name, min, max, *extra, &block)
33
33
  @not_empty = ConditionVariable.new
34
34
  @not_full = ConditionVariable.new
35
35
  @mutex = Mutex.new
@@ -39,6 +39,7 @@ module Puma
39
39
  @spawned = 0
40
40
  @waiting = 0
41
41
 
42
+ @name = name
42
43
  @min = Integer(min)
43
44
  @max = Integer(max)
44
45
  @block = block
@@ -71,7 +72,7 @@ module Puma
71
72
  attr_accessor :out_of_band_hook # @version 5.0.0
72
73
 
73
74
  def self.clean_thread_locals
74
- Thread.current.keys.each do |key| # rubocop: disable Performance/HashEachMethods
75
+ Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
75
76
  Thread.current[key] = nil unless key == :__recursive_key__
76
77
  end
77
78
  end
@@ -101,7 +102,7 @@ module Puma
101
102
  @spawned += 1
102
103
 
103
104
  th = Thread.new(@spawned) do |spawned|
104
- Puma.set_thread_name 'threadpool %03i' % spawned
105
+ Puma.set_thread_name '%s tp %03i' % [@name, spawned]
105
106
  todo = @todo
106
107
  block = @block
107
108
  mutex = @mutex
@@ -119,6 +120,7 @@ module Puma
119
120
  @trim_requested -= 1
120
121
  @spawned -= 1
121
122
  @workers.delete th
123
+ not_full.signal
122
124
  Thread.exit
123
125
  end
124
126
 
@@ -220,7 +222,7 @@ module Puma
220
222
  # then the `@todo` array would stay the same size as the reactor works
221
223
  # to try to buffer the request. In that scenario the next call to this
222
224
  # method would not block and another request would be added into the reactor
223
- # by the server. This would continue until a fully bufferend request
225
+ # by the server. This would continue until a fully buffered request
224
226
  # makes it through the reactor and can then be processed by the thread pool.
225
227
  def wait_until_not_full
226
228
  with_mutex do
@@ -240,11 +242,12 @@ module Puma
240
242
 
241
243
  # @version 5.0.0
242
244
  def wait_for_less_busy_worker(delay_s)
245
+ return unless delay_s && delay_s > 0
246
+
243
247
  # Ruby MRI does GVL, this can result
244
248
  # in processing contention when multiple threads
245
249
  # (requests) are running concurrently
246
250
  return unless Puma.mri?
247
- return unless delay_s > 0
248
251
 
249
252
  with_mutex do
250
253
  return if @shutdown
@@ -317,12 +320,12 @@ module Puma
317
320
  end
318
321
 
319
322
  def auto_trim!(timeout=30)
320
- @auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
323
+ @auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
321
324
  @auto_trim.start!
322
325
  end
323
326
 
324
327
  def auto_reap!(timeout=5)
325
- @reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
328
+ @reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
326
329
  @reaper.start!
327
330
  end
328
331
 
data/lib/puma/util.rb CHANGED
@@ -10,6 +10,13 @@ module Puma
10
10
  IO.pipe
11
11
  end
12
12
 
13
+ # An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
14
+ # which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
15
+ # Additional context: https://github.com/puma/puma/pull/1345
16
+ def purge_interrupt_queue
17
+ Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
18
+ end
19
+
13
20
  # Unescapes a URI escaped string with +encoding+. +encoding+ will be the
14
21
  # target encoding of the string returned, and it defaults to UTF-8
15
22
  if defined?(::Encoding)
@@ -61,7 +68,7 @@ module Puma
61
68
  end
62
69
  end
63
70
 
64
- return params
71
+ params
65
72
  end
66
73
 
67
74
  # A case-insensitive Hash that preserves the original case of a
data/lib/puma.rb CHANGED
@@ -12,12 +12,47 @@ require 'thread'
12
12
 
13
13
  require 'puma/puma_http11'
14
14
  require 'puma/detect'
15
+ require 'puma/json_serialization'
15
16
 
16
17
  module Puma
17
18
  autoload :Const, 'puma/const'
18
19
  autoload :Server, 'puma/server'
19
20
  autoload :Launcher, 'puma/launcher'
20
21
 
22
+ # at present, MiniSSL::Engine is only defined in extension code (puma_http11),
23
+ # not in minissl.rb
24
+ HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
25
+
26
+ HAS_UNIX_SOCKET = Object.const_defined? :UNIXSocket
27
+
28
+ if HAS_SSL
29
+ require 'puma/minissl'
30
+ else
31
+ module MiniSSL
32
+ # this class is defined so that it exists when Puma is compiled
33
+ # without ssl support, as Server and Reactor use it in rescue statements.
34
+ class SSLError < StandardError ; end
35
+ end
36
+ end
37
+
38
+ def self.ssl?
39
+ HAS_SSL
40
+ end
41
+
42
+ def self.abstract_unix_socket?
43
+ @abstract_unix ||=
44
+ if HAS_UNIX_SOCKET
45
+ begin
46
+ ::UNIXServer.new("\0puma.temp.unix").close
47
+ true
48
+ rescue ArgumentError # darwin
49
+ false
50
+ end
51
+ else
52
+ false
53
+ end
54
+ end
55
+
21
56
  # @!attribute [rw] stats_object=
22
57
  def self.stats_object=(val)
23
58
  @get_stats = val
@@ -25,8 +60,7 @@ module Puma
25
60
 
26
61
  # @!attribute [rw] stats_object
27
62
  def self.stats
28
- require 'json'
29
- @get_stats.stats.to_json
63
+ Puma::JSONSerialization.generate @get_stats.stats
30
64
  end
31
65
 
32
66
  # @!attribute [r] stats_hash
@@ -40,12 +74,4 @@ module Puma
40
74
  return unless Thread.current.respond_to?(:name=)
41
75
  Thread.current.name = "puma #{name}"
42
76
  end
43
-
44
- unless HAS_SSL
45
- module MiniSSL
46
- # this class is defined so that it exists when Puma is compiled
47
- # without ssl support, as Server and Reactor use it in rescue statements.
48
- class SSLError < StandardError ; end
49
- end
50
- end
51
77
  end
@@ -31,6 +31,7 @@ module Rack
31
31
 
32
32
  conf = ::Puma::Configuration.new(options, default_options) do |user_config, file_config, default_config|
33
33
  if options.delete(:Verbose)
34
+ require 'rack/common_logger'
34
35
  app = Rack::CommonLogger.new(app, STDOUT)
35
36
  end
36
37
 
data/tools/Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # Use this Dockerfile to create minimal reproductions of issues
2
2
 
3
- FROM ruby:2.6
3
+ FROM ruby:3.1
4
4
 
5
5
  # throw errors if Gemfile has been modified since Gemfile.lock
6
6
  RUN bundle config --global frozen 1
data/tools/trickletest.rb CHANGED
File without changes
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: 5.0.4
4
+ version: 5.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-27 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -24,9 +24,9 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
27
+ description: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server
28
28
  for Ruby/Rack applications. Puma is intended for use in both development and production
29
- environments. It's great for highly concurrent Ruby implementations such as Rubinius
29
+ environments. It's great for highly parallel Ruby implementations such as Rubinius
30
30
  and JRuby as well as as providing process worker support to support CRuby well.
31
31
  email:
32
32
  - evan@phx.io
@@ -44,6 +44,7 @@ files:
44
44
  - bin/puma-wild
45
45
  - bin/pumactl
46
46
  - docs/architecture.md
47
+ - docs/compile_options.md
47
48
  - docs/deployment.md
48
49
  - docs/fork_worker.md
49
50
  - docs/images/puma-connection-flow-no-reactor.png
@@ -53,10 +54,13 @@ files:
53
54
  - docs/jungle/rc.d/README.md
54
55
  - docs/jungle/rc.d/puma
55
56
  - docs/jungle/rc.d/puma.conf
57
+ - docs/kubernetes.md
56
58
  - docs/nginx.md
57
59
  - docs/plugins.md
60
+ - docs/rails_dev_mode.md
58
61
  - docs/restart.md
59
62
  - docs/signals.md
63
+ - docs/stats.md
60
64
  - docs/systemd.md
61
65
  - ext/puma_http11/PumaHttp11Service.java
62
66
  - ext/puma_http11/ext_help.h
@@ -90,6 +94,7 @@ files:
90
94
  - lib/puma/events.rb
91
95
  - lib/puma/io_buffer.rb
92
96
  - lib/puma/jruby_restart.rb
97
+ - lib/puma/json_serialization.rb
93
98
  - lib/puma/launcher.rb
94
99
  - lib/puma/minissl.rb
95
100
  - lib/puma/minissl/context_builder.rb
@@ -106,6 +111,7 @@ files:
106
111
  - lib/puma/server.rb
107
112
  - lib/puma/single.rb
108
113
  - lib/puma/state_file.rb
114
+ - lib/puma/systemd.rb
109
115
  - lib/puma/thread_pool.rb
110
116
  - lib/puma/util.rb
111
117
  - lib/rack/handler/puma.rb
@@ -119,7 +125,7 @@ metadata:
119
125
  changelog_uri: https://github.com/puma/puma/blob/master/History.md
120
126
  homepage_uri: https://puma.io
121
127
  source_code_uri: https://github.com/puma/puma
122
- post_install_message:
128
+ post_install_message:
123
129
  rdoc_options: []
124
130
  require_paths:
125
131
  - lib
@@ -134,9 +140,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
140
  - !ruby/object:Gem::Version
135
141
  version: '0'
136
142
  requirements: []
137
- rubygems_version: 3.0.3
138
- signing_key:
143
+ rubygems_version: 3.2.26
144
+ signing_key:
139
145
  specification_version: 4
140
- summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
146
+ summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
141
147
  Ruby/Rack applications
142
148
  test_files: []