puma 4.3.5 → 6.0.1

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1639 -519
  3. data/LICENSE +23 -20
  4. data/README.md +130 -42
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  9. data/docs/fork_worker.md +31 -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 +9 -0
  14. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  15. data/{tools → docs}/jungle/rc.d/puma +2 -2
  16. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +66 -0
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +15 -15
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +46 -23
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +85 -128
  25. data/docs/testing_benchmarks_local_files.md +150 -0
  26. data/docs/testing_test_rackup_ci_files.md +36 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +56 -11
  30. data/ext/puma_http11/http11_parser.c +69 -58
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +3 -3
  33. data/ext/puma_http11/http11_parser.rl +3 -3
  34. data/ext/puma_http11/http11_parser_common.rl +3 -3
  35. data/ext/puma_http11/mini_ssl.c +322 -130
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +52 -52
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  40. data/ext/puma_http11/puma_http11.c +47 -57
  41. data/lib/puma/app/status.rb +53 -37
  42. data/lib/puma/binder.rb +232 -119
  43. data/lib/puma/cli.rb +33 -33
  44. data/lib/puma/client.rb +197 -101
  45. data/lib/puma/cluster/worker.rb +175 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +224 -229
  48. data/lib/puma/commonlogger.rb +2 -2
  49. data/lib/puma/configuration.rb +112 -87
  50. data/lib/puma/const.rb +30 -25
  51. data/lib/puma/control_cli.rb +99 -79
  52. data/lib/puma/detect.rb +31 -2
  53. data/lib/puma/dsl.rb +426 -110
  54. data/lib/puma/error_logger.rb +112 -0
  55. data/lib/puma/events.rb +16 -115
  56. data/lib/puma/io_buffer.rb +44 -2
  57. data/lib/puma/jruby_restart.rb +2 -59
  58. data/lib/puma/json_serialization.rb +96 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  60. data/lib/puma/launcher.rb +170 -148
  61. data/lib/puma/log_writer.rb +137 -0
  62. data/lib/puma/minissl/context_builder.rb +35 -19
  63. data/lib/puma/minissl.rb +213 -55
  64. data/lib/puma/null_io.rb +18 -1
  65. data/lib/puma/plugin/tmp_restart.rb +1 -1
  66. data/lib/puma/plugin.rb +3 -12
  67. data/lib/puma/rack/builder.rb +5 -9
  68. data/lib/puma/rack/urlmap.rb +0 -0
  69. data/lib/puma/rack_default.rb +1 -1
  70. data/lib/puma/reactor.rb +85 -369
  71. data/lib/puma/request.rb +644 -0
  72. data/lib/puma/runner.rb +83 -77
  73. data/lib/puma/server.rb +303 -773
  74. data/lib/puma/single.rb +18 -74
  75. data/lib/puma/state_file.rb +45 -8
  76. data/lib/puma/systemd.rb +47 -0
  77. data/lib/puma/thread_pool.rb +136 -68
  78. data/lib/puma/util.rb +21 -4
  79. data/lib/puma.rb +54 -5
  80. data/lib/rack/handler/puma.rb +11 -12
  81. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  82. data/tools/trickletest.rb +0 -0
  83. metadata +36 -28
  84. data/docs/tcp_mode.md +0 -96
  85. data/ext/puma_http11/io_buffer.c +0 -155
  86. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  87. data/lib/puma/accept_nonblock.rb +0 -29
  88. data/lib/puma/tcp_logger.rb +0 -41
  89. data/tools/jungle/README.md +0 -19
  90. data/tools/jungle/init.d/README.md +0 -61
  91. data/tools/jungle/init.d/puma +0 -421
  92. data/tools/jungle/init.d/run-puma +0 -18
  93. data/tools/jungle/upstart/README.md +0 -61
  94. data/tools/jungle/upstart/puma-manager.conf +0 -31
  95. data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/runner.rb CHANGED
@@ -1,25 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/server'
4
- require 'puma/const'
5
- require 'puma/minissl/context_builder'
3
+ require_relative 'server'
4
+ require_relative 'const'
6
5
 
7
6
  module Puma
8
7
  # Generic class that is used by `Puma::Cluster` and `Puma::Single` to
9
8
  # serve requests. This class spawns a new instance of `Puma::Server` via
10
9
  # a call to `start_server`.
11
10
  class Runner
12
- def initialize(cli, events)
13
- @launcher = cli
14
- @events = events
15
- @options = cli.options
11
+ def initialize(launcher)
12
+ @launcher = launcher
13
+ @log_writer = launcher.log_writer
14
+ @events = launcher.events
15
+ @config = launcher.config
16
+ @options = launcher.options
16
17
  @app = nil
17
18
  @control = nil
18
19
  @started_at = Time.now
20
+ @wakeup = nil
19
21
  end
20
22
 
21
- def daemon?
22
- @options[:daemon]
23
+ # Returns the hash of configuration options.
24
+ # @return [Puma::UserFileDefaultOptions]
25
+ attr_reader :options
26
+
27
+ def wakeup!
28
+ return unless @wakeup
29
+
30
+ @wakeup.write "!" unless @wakeup.closed?
31
+
32
+ rescue SystemCallError, IOError
33
+ Puma::Util.purge_interrupt_queue
23
34
  end
24
35
 
25
36
  def development?
@@ -31,28 +42,27 @@ module Puma
31
42
  end
32
43
 
33
44
  def log(str)
34
- @events.log str
45
+ @log_writer.log str
35
46
  end
36
47
 
37
- def before_restart
38
- @control.stop(true) if @control
48
+ # @version 5.0.0
49
+ def stop_control
50
+ @control&.stop true
39
51
  end
40
52
 
41
53
  def error(str)
42
- @events.error str
54
+ @log_writer.error str
43
55
  end
44
56
 
45
57
  def debug(str)
46
- @events.log "- #{str}" if @options[:debug]
58
+ @log_writer.log "- #{str}" if @options[:debug]
47
59
  end
48
60
 
49
61
  def start_control
50
62
  str = @options[:control_url]
51
63
  return unless str
52
64
 
53
- require 'puma/app/status'
54
-
55
- uri = URI.parse str
65
+ require_relative 'app/status'
56
66
 
57
67
  if token = @options[:control_auth_token]
58
68
  token = nil if token.empty? || token == 'none'
@@ -60,34 +70,23 @@ module Puma
60
70
 
61
71
  app = Puma::App::Status.new @launcher, token
62
72
 
63
- control = Puma::Server.new app, @launcher.events
64
- control.min_threads = 0
65
- control.max_threads = 1
66
-
67
- case uri.scheme
68
- when "ssl"
69
- log "* Starting control server on #{str}"
70
- params = Util.parse_query uri.query
71
- ctx = MiniSSL::ContextBuilder.new(params, @events).context
72
-
73
- control.add_ssl_listener uri.host, uri.port, ctx
74
- when "tcp"
75
- log "* Starting control server on #{str}"
76
- control.add_tcp_listener uri.host, uri.port
77
- when "unix"
78
- log "* Starting control server on #{str}"
79
- path = "#{uri.host}#{uri.path}"
80
- mask = @options[:control_url_umask]
81
-
82
- control.add_unix_listener path, mask
83
- else
84
- error "Invalid control URI: #{str}"
85
- end
73
+ # A Reactor is not created aand nio4r is not loaded when 'queue_requests: false'
74
+ # Use `nil` for events, no hooks in control server
75
+ control = Puma::Server.new app, nil,
76
+ { min_threads: 0, max_threads: 1, queue_requests: false, log_writer: @log_writer }
86
77
 
87
- control.run
78
+ control.binder.parse [str], nil, 'Starting control server'
79
+
80
+ control.run thread_name: 'ctl'
88
81
  @control = control
89
82
  end
90
83
 
84
+ # @version 5.0.0
85
+ def close_control_listeners
86
+ @control.binder.close_listeners if @control
87
+ end
88
+
89
+ # @!attribute [r] ruby_engine
91
90
  def ruby_engine
92
91
  if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
93
92
  "ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
@@ -103,14 +102,18 @@ module Puma
103
102
  def output_header(mode)
104
103
  min_t = @options[:min_threads]
105
104
  max_t = @options[:max_threads]
105
+ environment = @options[:environment]
106
106
 
107
107
  log "Puma starting in #{mode} mode..."
108
- log "* Version #{Puma::Const::PUMA_VERSION} (#{ruby_engine}), codename: #{Puma::Const::CODE_NAME}"
109
- log "* Min threads: #{min_t}, max threads: #{max_t}"
110
- log "* Environment: #{ENV['RACK_ENV']}"
108
+ log "* Puma version: #{Puma::Const::PUMA_VERSION} (#{ruby_engine}) (\"#{Puma::Const::CODE_NAME}\")"
109
+ log "* Min threads: #{min_t}"
110
+ log "* Max threads: #{max_t}"
111
+ log "* Environment: #{environment}"
111
112
 
112
- if @options[:mode] == :tcp
113
- log "* Mode: Lopez Express (tcp)"
113
+ if mode == "cluster"
114
+ log "* Master PID: #{Process.pid}"
115
+ else
116
+ log "* PID: #{Process.pid}"
114
117
  end
115
118
  end
116
119
 
@@ -124,69 +127,72 @@ module Puma
124
127
  append = @options[:redirect_append]
125
128
 
126
129
  if stdout
127
- unless Dir.exist?(File.dirname(stdout))
128
- raise "Cannot redirect STDOUT to #{stdout}"
129
- end
130
+ ensure_output_directory_exists(stdout, 'STDOUT')
130
131
 
131
132
  STDOUT.reopen stdout, (append ? "a" : "w")
132
- STDOUT.sync = true
133
133
  STDOUT.puts "=== puma startup: #{Time.now} ==="
134
+ STDOUT.flush unless STDOUT.sync
134
135
  end
135
136
 
136
137
  if stderr
137
- unless Dir.exist?(File.dirname(stderr))
138
- raise "Cannot redirect STDERR to #{stderr}"
139
- end
138
+ ensure_output_directory_exists(stderr, 'STDERR')
140
139
 
141
140
  STDERR.reopen stderr, (append ? "a" : "w")
142
- STDERR.sync = true
143
141
  STDERR.puts "=== puma startup: #{Time.now} ==="
142
+ STDERR.flush unless STDERR.sync
143
+ end
144
+
145
+ if @options[:mutate_stdout_and_stderr_to_sync_on_write]
146
+ STDOUT.sync = true
147
+ STDERR.sync = true
144
148
  end
145
149
  end
146
150
 
147
151
  def load_and_bind
148
- unless @launcher.config.app_configured?
152
+ unless @config.app_configured?
149
153
  error "No application configured, nothing to run"
150
154
  exit 1
151
155
  end
152
156
 
153
- # Load the app before we daemonize.
154
157
  begin
155
- @app = @launcher.config.app
158
+ @app = @config.app
156
159
  rescue Exception => e
157
160
  log "! Unable to load application: #{e.class}: #{e.message}"
158
161
  raise e
159
162
  end
160
163
 
161
- @launcher.binder.parse @options[:binds], self
164
+ @launcher.binder.parse @options[:binds]
162
165
  end
163
166
 
167
+ # @!attribute [r] app
164
168
  def app
165
- @app ||= @launcher.config.app
169
+ @app ||= @config.app
166
170
  end
167
171
 
168
172
  def start_server
169
- min_t = @options[:min_threads]
170
- max_t = @options[:max_threads]
171
-
172
- server = Puma::Server.new app, @launcher.events, @options
173
- server.min_threads = min_t
174
- server.max_threads = max_t
175
- server.inherit_binder @launcher.binder
176
-
177
- if @options[:mode] == :tcp
178
- server.tcp_mode!
179
- end
180
-
181
- if @options[:early_hints]
182
- server.early_hints = true
183
- end
173
+ server = Puma::Server.new(app, @events, @options)
174
+ server.inherit_binder(@launcher.binder)
175
+ server
176
+ end
184
177
 
185
- unless development? || test?
186
- server.leak_stack_on_error = false
178
+ private
179
+ def ensure_output_directory_exists(path, io_name)
180
+ unless Dir.exist?(File.dirname(path))
181
+ raise "Cannot redirect #{io_name} to #{path}"
187
182
  end
183
+ end
188
184
 
189
- server
185
+ def stats
186
+ {
187
+ versions: {
188
+ puma: Puma::Const::PUMA_VERSION,
189
+ ruby: {
190
+ engine: RUBY_ENGINE,
191
+ version: RUBY_VERSION,
192
+ patchlevel: RUBY_PATCHLEVEL
193
+ }
194
+ }
195
+ }
190
196
  end
191
197
  end
192
198
  end