puma 4.3.12-java → 5.0.0.beta1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +58 -41
- data/LICENSE +23 -20
- data/README.md +17 -11
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +0 -0
- data/docs/deployment.md +3 -1
- data/docs/fork_worker.md +31 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +13 -0
- data/{tools → docs}/jungle/rc.d/README.md +0 -0
- data/{tools → docs}/jungle/rc.d/puma +0 -0
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +0 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +0 -0
- data/docs/restart.md +0 -0
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -63
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +3 -10
- data/ext/puma_http11/http11_parser.c +11 -26
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +1 -3
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +47 -82
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +46 -48
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +0 -0
- data/ext/puma_http11/puma_http11.c +2 -38
- data/lib/puma/accept_nonblock.rb +0 -0
- data/lib/puma/app/status.rb +16 -5
- data/lib/puma/binder.rb +62 -60
- data/lib/puma/cli.rb +7 -15
- data/lib/puma/client.rb +38 -78
- data/lib/puma/cluster.rb +179 -74
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +30 -42
- data/lib/puma/const.rb +5 -8
- data/lib/puma/control_cli.rb +27 -17
- data/lib/puma/detect.rb +8 -0
- data/lib/puma/dsl.rb +70 -34
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/launcher.rb +41 -29
- data/lib/puma/minissl/context_builder.rb +0 -0
- data/lib/puma/minissl.rb +13 -8
- data/lib/puma/null_io.rb +1 -1
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +0 -0
- data/lib/puma/reactor.rb +6 -1
- data/lib/puma/runner.rb +5 -34
- data/lib/puma/server.rb +74 -206
- data/lib/puma/single.rb +7 -64
- data/lib/puma/state_file.rb +5 -2
- data/lib/puma/thread_pool.rb +85 -47
- data/lib/puma/util.rb +0 -0
- data/lib/puma.rb +4 -0
- data/lib/rack/handler/puma.rb +1 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- data/tools/trickletest.rb +0 -0
- metadata +18 -22
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
    
        data/lib/puma/cluster.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ require 'puma/util' | |
| 5 5 | 
             
            require 'puma/plugin'
         | 
| 6 6 |  | 
| 7 7 | 
             
            require 'time'
         | 
| 8 | 
            +
            require 'json'
         | 
| 8 9 |  | 
| 9 10 | 
             
            module Puma
         | 
| 10 11 | 
             
              # This class is instantiated by the `Puma::Launcher` and used
         | 
| @@ -24,9 +25,8 @@ module Puma | |
| 24 25 |  | 
| 25 26 | 
             
                  @phase = 0
         | 
| 26 27 | 
             
                  @workers = []
         | 
| 27 | 
            -
                  @next_check =  | 
| 28 | 
            +
                  @next_check = Time.now
         | 
| 28 29 |  | 
| 29 | 
            -
                  @phased_state = :idle
         | 
| 30 30 | 
             
                  @phased_restart = false
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| @@ -37,7 +37,7 @@ module Puma | |
| 37 37 | 
             
                  begin
         | 
| 38 38 | 
             
                    loop do
         | 
| 39 39 | 
             
                      wait_workers
         | 
| 40 | 
            -
                      break if @workers.empty?
         | 
| 40 | 
            +
                      break if @workers.reject {|w| w.pid.nil?}.empty?
         | 
| 41 41 | 
             
                      sleep 0.2
         | 
| 42 42 | 
             
                    end
         | 
| 43 43 | 
             
                  rescue Interrupt
         | 
| @@ -73,11 +73,12 @@ module Puma | |
| 73 73 | 
             
                    @first_term_sent = nil
         | 
| 74 74 | 
             
                    @started_at = Time.now
         | 
| 75 75 | 
             
                    @last_checkin = Time.now
         | 
| 76 | 
            -
                    @last_status =  | 
| 76 | 
            +
                    @last_status = {}
         | 
| 77 77 | 
             
                    @term = false
         | 
| 78 78 | 
             
                  end
         | 
| 79 79 |  | 
| 80 80 | 
             
                  attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
         | 
| 81 | 
            +
                  attr_writer :pid, :phase
         | 
| 81 82 |  | 
| 82 83 | 
             
                  def booted?
         | 
| 83 84 | 
             
                    @stage == :booted
         | 
| @@ -94,11 +95,15 @@ module Puma | |
| 94 95 |  | 
| 95 96 | 
             
                  def ping!(status)
         | 
| 96 97 | 
             
                    @last_checkin = Time.now
         | 
| 97 | 
            -
                    @last_status = status
         | 
| 98 | 
            +
                    @last_status = JSON.parse(status, symbolize_names: true)
         | 
| 98 99 | 
             
                  end
         | 
| 99 100 |  | 
| 100 | 
            -
                  def ping_timeout | 
| 101 | 
            -
                     | 
| 101 | 
            +
                  def ping_timeout
         | 
| 102 | 
            +
                    @last_checkin +
         | 
| 103 | 
            +
                      (booted? ?
         | 
| 104 | 
            +
                        @options[:worker_timeout] :
         | 
| 105 | 
            +
                        @options[:worker_boot_timeout]
         | 
| 106 | 
            +
                      )
         | 
| 102 107 | 
             
                  end
         | 
| 103 108 |  | 
| 104 109 | 
             
                  def term
         | 
| @@ -109,14 +114,14 @@ module Puma | |
| 109 114 | 
             
                        @term ||= true
         | 
| 110 115 | 
             
                        @first_term_sent ||= Time.now
         | 
| 111 116 | 
             
                      end
         | 
| 112 | 
            -
                      Process.kill @signal, @pid
         | 
| 117 | 
            +
                      Process.kill @signal, @pid if @pid
         | 
| 113 118 | 
             
                    rescue Errno::ESRCH
         | 
| 114 119 | 
             
                    end
         | 
| 115 120 | 
             
                  end
         | 
| 116 121 |  | 
| 117 122 | 
             
                  def kill
         | 
| 118 | 
            -
                     | 
| 119 | 
            -
             | 
| 123 | 
            +
                    @signal = 'KILL'
         | 
| 124 | 
            +
                    term
         | 
| 120 125 | 
             
                  end
         | 
| 121 126 |  | 
| 122 127 | 
             
                  def hup
         | 
| @@ -130,27 +135,43 @@ module Puma | |
| 130 135 | 
             
                  return if diff < 1
         | 
| 131 136 |  | 
| 132 137 | 
             
                  master = Process.pid
         | 
| 138 | 
            +
                  if @options[:fork_worker]
         | 
| 139 | 
            +
                    @fork_writer << "-1\n"
         | 
| 140 | 
            +
                  end
         | 
| 133 141 |  | 
| 134 142 | 
             
                  diff.times do
         | 
| 135 143 | 
             
                    idx = next_worker_index
         | 
| 136 | 
            -
                    @launcher.config.run_hooks :before_worker_fork, idx
         | 
| 137 144 |  | 
| 138 | 
            -
                     | 
| 139 | 
            -
             | 
| 140 | 
            -
                       | 
| 141 | 
            -
             | 
| 142 | 
            -
                       | 
| 145 | 
            +
                    if @options[:fork_worker] && idx != 0
         | 
| 146 | 
            +
                      @fork_writer << "#{idx}\n"
         | 
| 147 | 
            +
                      pid = nil
         | 
| 148 | 
            +
                    else
         | 
| 149 | 
            +
                      pid = spawn_worker(idx, master)
         | 
| 143 150 | 
             
                    end
         | 
| 144 151 |  | 
| 145 152 | 
             
                    debug "Spawned worker: #{pid}"
         | 
| 146 153 | 
             
                    @workers << Worker.new(idx, pid, @phase, @options)
         | 
| 154 | 
            +
                  end
         | 
| 147 155 |  | 
| 148 | 
            -
             | 
| 156 | 
            +
                  if @options[:fork_worker] &&
         | 
| 157 | 
            +
                    @workers.all? {|x| x.phase == @phase}
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                    @fork_writer << "0\n"
         | 
| 149 160 | 
             
                  end
         | 
| 161 | 
            +
                end
         | 
| 150 162 |  | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 163 | 
            +
                def spawn_worker(idx, master)
         | 
| 164 | 
            +
                  @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  pid = fork { worker(idx, master) }
         | 
| 167 | 
            +
                  if !pid
         | 
| 168 | 
            +
                    log "! Complete inability to spawn new workers detected"
         | 
| 169 | 
            +
                    log "! Seppuku is the only choice."
         | 
| 170 | 
            +
                    exit! 1
         | 
| 153 171 | 
             
                  end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
         | 
| 174 | 
            +
                  pid
         | 
| 154 175 | 
             
                end
         | 
| 155 176 |  | 
| 156 177 | 
             
                def cull_workers
         | 
| @@ -179,26 +200,12 @@ module Puma | |
| 179 200 | 
             
                  @workers.count { |w| !w.booted? } == 0
         | 
| 180 201 | 
             
                end
         | 
| 181 202 |  | 
| 182 | 
            -
                def check_workers | 
| 183 | 
            -
                  return if  | 
| 203 | 
            +
                def check_workers
         | 
| 204 | 
            +
                  return if @next_check >= Time.now
         | 
| 184 205 |  | 
| 185 206 | 
             
                  @next_check = Time.now + Const::WORKER_CHECK_INTERVAL
         | 
| 186 207 |  | 
| 187 | 
            -
                   | 
| 188 | 
            -
             | 
| 189 | 
            -
                  @workers.each do |w|
         | 
| 190 | 
            -
                    next if !w.booted? && !w.ping_timeout?(@options[:worker_boot_timeout])
         | 
| 191 | 
            -
                    if w.ping_timeout?(@options[:worker_timeout])
         | 
| 192 | 
            -
                      log "! Terminating timed out worker: #{w.pid}"
         | 
| 193 | 
            -
                      w.kill
         | 
| 194 | 
            -
                      any = true
         | 
| 195 | 
            -
                    end
         | 
| 196 | 
            -
                  end
         | 
| 197 | 
            -
             | 
| 198 | 
            -
                  # If we killed any timed out workers, try to catch them
         | 
| 199 | 
            -
                  # during this loop by giving the kernel time to kill them.
         | 
| 200 | 
            -
                  sleep 1 if any
         | 
| 201 | 
            -
             | 
| 208 | 
            +
                  timeout_workers
         | 
| 202 209 | 
             
                  wait_workers
         | 
| 203 210 | 
             
                  cull_workers
         | 
| 204 211 | 
             
                  spawn_workers
         | 
| @@ -211,17 +218,18 @@ module Puma | |
| 211 218 | 
             
                    w = @workers.find { |x| x.phase != @phase }
         | 
| 212 219 |  | 
| 213 220 | 
             
                    if w
         | 
| 214 | 
            -
                       | 
| 215 | 
            -
                        @phased_state = :waiting
         | 
| 216 | 
            -
                        log "- Stopping #{w.pid} for phased upgrade..."
         | 
| 217 | 
            -
                      end
         | 
| 218 | 
            -
             | 
| 221 | 
            +
                      log "- Stopping #{w.pid} for phased upgrade..."
         | 
| 219 222 | 
             
                      unless w.term?
         | 
| 220 223 | 
             
                        w.term
         | 
| 221 224 | 
             
                        log "- #{w.signal} sent to #{w.pid}..."
         | 
| 222 225 | 
             
                      end
         | 
| 223 226 | 
             
                    end
         | 
| 224 227 | 
             
                  end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                  @next_check = [
         | 
| 230 | 
            +
                    @workers.reject(&:term?).map(&:ping_timeout).min,
         | 
| 231 | 
            +
                    @next_check
         | 
| 232 | 
            +
                  ].compact.min
         | 
| 225 233 | 
             
                end
         | 
| 226 234 |  | 
| 227 235 | 
             
                def wakeup!
         | 
| @@ -241,9 +249,14 @@ module Puma | |
| 241 249 |  | 
| 242 250 | 
             
                  Signal.trap "SIGINT", "IGNORE"
         | 
| 243 251 |  | 
| 252 | 
            +
                  fork_worker = @options[:fork_worker] && index == 0
         | 
| 253 | 
            +
             | 
| 244 254 | 
             
                  @workers = []
         | 
| 245 | 
            -
                   | 
| 246 | 
            -
             | 
| 255 | 
            +
                  if !@options[:fork_worker] || fork_worker
         | 
| 256 | 
            +
                    @master_read.close
         | 
| 257 | 
            +
                    @suicide_pipe.close
         | 
| 258 | 
            +
                    @fork_writer.close
         | 
| 259 | 
            +
                  end
         | 
| 247 260 |  | 
| 248 261 | 
             
                  Thread.new do
         | 
| 249 262 | 
             
                    Puma.set_thread_name "worker check pipe"
         | 
| @@ -264,17 +277,47 @@ module Puma | |
| 264 277 |  | 
| 265 278 | 
             
                  # Invoke any worker boot hooks so they can get
         | 
| 266 279 | 
             
                  # things in shape before booting the app.
         | 
| 267 | 
            -
                  @launcher.config.run_hooks :before_worker_boot, index
         | 
| 280 | 
            +
                  @launcher.config.run_hooks :before_worker_boot, index, @launcher.events
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  server = @server ||= start_server
         | 
| 283 | 
            +
                  restart_server = Queue.new << true << false
         | 
| 268 284 |  | 
| 269 | 
            -
                   | 
| 285 | 
            +
                  if fork_worker
         | 
| 286 | 
            +
                    restart_server.clear
         | 
| 287 | 
            +
                    Signal.trap "SIGCHLD" do
         | 
| 288 | 
            +
                      Process.wait(-1, Process::WNOHANG) rescue nil
         | 
| 289 | 
            +
                      wakeup!
         | 
| 290 | 
            +
                    end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                    Thread.new do
         | 
| 293 | 
            +
                      Puma.set_thread_name "worker fork pipe"
         | 
| 294 | 
            +
                      while (idx = @fork_pipe.gets)
         | 
| 295 | 
            +
                        idx = idx.to_i
         | 
| 296 | 
            +
                        if idx == -1 # stop server
         | 
| 297 | 
            +
                          if restart_server.length > 0
         | 
| 298 | 
            +
                            restart_server.clear
         | 
| 299 | 
            +
                            server.begin_restart(true)
         | 
| 300 | 
            +
                            @launcher.config.run_hooks :before_refork, nil, @launcher.events
         | 
| 301 | 
            +
                            nakayoshi_gc
         | 
| 302 | 
            +
                          end
         | 
| 303 | 
            +
                        elsif idx == 0 # restart server
         | 
| 304 | 
            +
                          restart_server << true << false
         | 
| 305 | 
            +
                        else # fork worker
         | 
| 306 | 
            +
                          pid = spawn_worker(idx, master)
         | 
| 307 | 
            +
                          @worker_write << "f#{pid}:#{idx}\n" rescue nil
         | 
| 308 | 
            +
                        end
         | 
| 309 | 
            +
                      end
         | 
| 310 | 
            +
                    end
         | 
| 311 | 
            +
                  end
         | 
| 270 312 |  | 
| 271 313 | 
             
                  Signal.trap "SIGTERM" do
         | 
| 272 314 | 
             
                    @worker_write << "e#{Process.pid}\n" rescue nil
         | 
| 273 315 | 
             
                    server.stop
         | 
| 316 | 
            +
                    restart_server << false
         | 
| 274 317 | 
             
                  end
         | 
| 275 318 |  | 
| 276 319 | 
             
                  begin
         | 
| 277 | 
            -
                    @worker_write << "b#{Process.pid}\n"
         | 
| 320 | 
            +
                    @worker_write << "b#{Process.pid}:#{index}\n"
         | 
| 278 321 | 
             
                  rescue SystemCallError, IOError
         | 
| 279 322 | 
             
                    Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
         | 
| 280 323 | 
             
                    STDERR.puts "Master seems to have exited, exiting."
         | 
| @@ -283,17 +326,11 @@ module Puma | |
| 283 326 |  | 
| 284 327 | 
             
                  Thread.new(@worker_write) do |io|
         | 
| 285 328 | 
             
                    Puma.set_thread_name "stat payload"
         | 
| 286 | 
            -
                    base_payload = "p#{Process.pid}"
         | 
| 287 329 |  | 
| 288 330 | 
             
                    while true
         | 
| 289 331 | 
             
                      sleep Const::WORKER_CHECK_INTERVAL
         | 
| 290 332 | 
             
                      begin
         | 
| 291 | 
            -
                         | 
| 292 | 
            -
                        r = server.running || 0
         | 
| 293 | 
            -
                        t = server.pool_capacity || 0
         | 
| 294 | 
            -
                        m = server.max_threads || 0
         | 
| 295 | 
            -
                        payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m} }\n!
         | 
| 296 | 
            -
                        io << payload
         | 
| 333 | 
            +
                        io << "p#{Process.pid}#{server.stats.to_json}\n"
         | 
| 297 334 | 
             
                      rescue IOError
         | 
| 298 335 | 
             
                        Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
         | 
| 299 336 | 
             
                        break
         | 
| @@ -301,11 +338,11 @@ module Puma | |
| 301 338 | 
             
                    end
         | 
| 302 339 | 
             
                  end
         | 
| 303 340 |  | 
| 304 | 
            -
                  server.run.join
         | 
| 341 | 
            +
                  server.run.join while restart_server.pop
         | 
| 305 342 |  | 
| 306 343 | 
             
                  # Invoke any worker shutdown hooks so they can prevent the worker
         | 
| 307 344 | 
             
                  # exiting until any background operations are completed
         | 
| 308 | 
            -
                  @launcher.config.run_hooks :before_worker_shutdown, index
         | 
| 345 | 
            +
                  @launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
         | 
| 309 346 | 
             
                ensure
         | 
| 310 347 | 
             
                  @worker_write << "t#{Process.pid}\n" rescue nil
         | 
| 311 348 | 
             
                  @worker_write.close
         | 
| @@ -352,18 +389,57 @@ module Puma | |
| 352 389 | 
             
                # the master process.
         | 
| 353 390 | 
             
                def stats
         | 
| 354 391 | 
             
                  old_worker_count = @workers.count { |w| w.phase != @phase }
         | 
| 355 | 
            -
                   | 
| 356 | 
            -
             | 
| 357 | 
            -
             | 
| 392 | 
            +
                  worker_status = @workers.map do |w|
         | 
| 393 | 
            +
                    {
         | 
| 394 | 
            +
                      started_at: w.started_at.utc.iso8601,
         | 
| 395 | 
            +
                      pid: w.pid,
         | 
| 396 | 
            +
                      index: w.index,
         | 
| 397 | 
            +
                      phase: w.phase,
         | 
| 398 | 
            +
                      booted: w.booted?,
         | 
| 399 | 
            +
                      last_checkin: w.last_checkin.utc.iso8601,
         | 
| 400 | 
            +
                      last_status: w.last_status,
         | 
| 401 | 
            +
                    }
         | 
| 402 | 
            +
                  end
         | 
| 403 | 
            +
             | 
| 404 | 
            +
                  {
         | 
| 405 | 
            +
                    started_at: @started_at.utc.iso8601,
         | 
| 406 | 
            +
                    workers: @workers.size,
         | 
| 407 | 
            +
                    phase: @phase,
         | 
| 408 | 
            +
                    booted_workers: worker_status.count { |w| w[:booted] },
         | 
| 409 | 
            +
                    old_workers: old_worker_count,
         | 
| 410 | 
            +
                    worker_status: worker_status,
         | 
| 411 | 
            +
                  }
         | 
| 358 412 | 
             
                end
         | 
| 359 413 |  | 
| 360 414 | 
             
                def preload?
         | 
| 361 415 | 
             
                  @options[:preload_app]
         | 
| 362 416 | 
             
                end
         | 
| 363 417 |  | 
| 418 | 
            +
                def fork_worker!
         | 
| 419 | 
            +
                  if (worker = @workers.find { |w| w.index == 0 })
         | 
| 420 | 
            +
                    worker.phase += 1
         | 
| 421 | 
            +
                  end
         | 
| 422 | 
            +
                  phased_restart
         | 
| 423 | 
            +
                end
         | 
| 424 | 
            +
             | 
| 364 425 | 
             
                # We do this in a separate method to keep the lambda scope
         | 
| 365 426 | 
             
                # of the signals handlers as small as possible.
         | 
| 366 427 | 
             
                def setup_signals
         | 
| 428 | 
            +
                  if @options[:fork_worker]
         | 
| 429 | 
            +
                    Signal.trap "SIGURG" do
         | 
| 430 | 
            +
                      fork_worker!
         | 
| 431 | 
            +
                    end
         | 
| 432 | 
            +
             | 
| 433 | 
            +
                    # Auto-fork after the specified number of requests.
         | 
| 434 | 
            +
                    if (fork_requests = @options[:fork_worker].to_i) > 0
         | 
| 435 | 
            +
                      @launcher.events.register(:ping!) do |w|
         | 
| 436 | 
            +
                        fork_worker! if w.index == 0 &&
         | 
| 437 | 
            +
                          w.phase == 0 &&
         | 
| 438 | 
            +
                          w.last_status[:requests_count] >= fork_requests
         | 
| 439 | 
            +
                      end
         | 
| 440 | 
            +
                    end
         | 
| 441 | 
            +
                  end
         | 
| 442 | 
            +
             | 
| 367 443 | 
             
                  Signal.trap "SIGCHLD" do
         | 
| 368 444 | 
             
                    wakeup!
         | 
| 369 445 | 
             
                  end
         | 
| @@ -447,12 +523,11 @@ module Puma | |
| 447 523 | 
             
                  #
         | 
| 448 524 | 
             
                  @check_pipe, @suicide_pipe = Puma::Util.pipe
         | 
| 449 525 |  | 
| 450 | 
            -
                   | 
| 451 | 
            -
             | 
| 452 | 
            -
             | 
| 453 | 
            -
             | 
| 454 | 
            -
             | 
| 455 | 
            -
                  end
         | 
| 526 | 
            +
                  # Separate pipe used by worker 0 to receive commands to
         | 
| 527 | 
            +
                  # fork new worker processes.
         | 
| 528 | 
            +
                  @fork_pipe, @fork_writer = Puma::Util.pipe
         | 
| 529 | 
            +
             | 
| 530 | 
            +
                  log "Use Ctrl-C to stop"
         | 
| 456 531 |  | 
| 457 532 | 
             
                  redirect_io
         | 
| 458 533 |  | 
| @@ -464,7 +539,8 @@ module Puma | |
| 464 539 |  | 
| 465 540 | 
             
                  @master_read, @worker_write = read, @wakeup
         | 
| 466 541 |  | 
| 467 | 
            -
                  @launcher.config.run_hooks :before_fork, nil
         | 
| 542 | 
            +
                  @launcher.config.run_hooks :before_fork, nil, @launcher.events
         | 
| 543 | 
            +
                  nakayoshi_gc
         | 
| 468 544 |  | 
| 469 545 | 
             
                  spawn_workers
         | 
| 470 546 |  | 
| @@ -475,8 +551,6 @@ module Puma | |
| 475 551 | 
             
                  @launcher.events.fire_on_booted!
         | 
| 476 552 |  | 
| 477 553 | 
             
                  begin
         | 
| 478 | 
            -
                    force_check = false
         | 
| 479 | 
            -
             | 
| 480 554 | 
             
                    while @status == :run
         | 
| 481 555 | 
             
                      begin
         | 
| 482 556 | 
             
                        if @phased_restart
         | 
| @@ -484,34 +558,39 @@ module Puma | |
| 484 558 | 
             
                          @phased_restart = false
         | 
| 485 559 | 
             
                        end
         | 
| 486 560 |  | 
| 487 | 
            -
                        check_workers | 
| 561 | 
            +
                        check_workers
         | 
| 488 562 |  | 
| 489 | 
            -
                         | 
| 490 | 
            -
             | 
| 491 | 
            -
                        res = IO.select([read], nil, nil, Const::WORKER_CHECK_INTERVAL)
         | 
| 563 | 
            +
                        res = IO.select([read], nil, nil, [0, @next_check - Time.now].max)
         | 
| 492 564 |  | 
| 493 565 | 
             
                        if res
         | 
| 494 566 | 
             
                          req = read.read_nonblock(1)
         | 
| 495 567 |  | 
| 568 | 
            +
                          @next_check = Time.now if req == "!"
         | 
| 496 569 | 
             
                          next if !req || req == "!"
         | 
| 497 570 |  | 
| 498 571 | 
             
                          result = read.gets
         | 
| 499 572 | 
             
                          pid = result.to_i
         | 
| 500 573 |  | 
| 574 | 
            +
                          if req == "b" || req == "f"
         | 
| 575 | 
            +
                            pid, idx = result.split(':').map(&:to_i)
         | 
| 576 | 
            +
                            w = @workers.find {|x| x.index == idx}
         | 
| 577 | 
            +
                            w.pid = pid if w.pid.nil?
         | 
| 578 | 
            +
                          end
         | 
| 579 | 
            +
             | 
| 501 580 | 
             
                          if w = @workers.find { |x| x.pid == pid }
         | 
| 502 581 | 
             
                            case req
         | 
| 503 582 | 
             
                            when "b"
         | 
| 504 583 | 
             
                              w.boot!
         | 
| 505 584 | 
             
                              log "- Worker #{w.index} (pid: #{pid}) booted, phase: #{w.phase}"
         | 
| 506 | 
            -
                               | 
| 585 | 
            +
                              @next_check = Time.now
         | 
| 507 586 | 
             
                            when "e"
         | 
| 508 587 | 
             
                              # external term, see worker method, Signal.trap "SIGTERM"
         | 
| 509 588 | 
             
                              w.instance_variable_set :@term, true
         | 
| 510 589 | 
             
                            when "t"
         | 
| 511 590 | 
             
                              w.term unless w.term?
         | 
| 512 | 
            -
                              force_check = true
         | 
| 513 591 | 
             
                            when "p"
         | 
| 514 592 | 
             
                              w.ping!(result.sub(/^\d+/,'').chomp)
         | 
| 593 | 
            +
                              @launcher.events.fire(:ping!, w)
         | 
| 515 594 | 
             
                            end
         | 
| 516 595 | 
             
                          else
         | 
| 517 596 | 
             
                            log "! Out-of-sync worker list, no #{pid} worker"
         | 
| @@ -538,6 +617,7 @@ module Puma | |
| 538 617 | 
             
                # `#term` if needed
         | 
| 539 618 | 
             
                def wait_workers
         | 
| 540 619 | 
             
                  @workers.reject! do |w|
         | 
| 620 | 
            +
                    next false if w.pid.nil?
         | 
| 541 621 | 
             
                    begin
         | 
| 542 622 | 
             
                      if Process.wait(w.pid, Process::WNOHANG)
         | 
| 543 623 | 
             
                        true
         | 
| @@ -546,9 +626,34 @@ module Puma | |
| 546 626 | 
             
                        nil
         | 
| 547 627 | 
             
                      end
         | 
| 548 628 | 
             
                    rescue Errno::ECHILD
         | 
| 549 | 
            -
                       | 
| 629 | 
            +
                      begin
         | 
| 630 | 
            +
                        Process.kill(0, w.pid)
         | 
| 631 | 
            +
                        false # child still alive, but has another parent
         | 
| 632 | 
            +
                      rescue Errno::ESRCH, Errno::EPERM
         | 
| 633 | 
            +
                        true # child is already terminated
         | 
| 634 | 
            +
                      end
         | 
| 550 635 | 
             
                    end
         | 
| 551 636 | 
             
                  end
         | 
| 552 637 | 
             
                end
         | 
| 638 | 
            +
             | 
| 639 | 
            +
                def timeout_workers
         | 
| 640 | 
            +
                  @workers.each do |w|
         | 
| 641 | 
            +
                    if !w.term? && w.ping_timeout <= Time.now
         | 
| 642 | 
            +
                      log "! Terminating timed out worker: #{w.pid}"
         | 
| 643 | 
            +
                      w.kill
         | 
| 644 | 
            +
                    end
         | 
| 645 | 
            +
                  end
         | 
| 646 | 
            +
                end
         | 
| 647 | 
            +
             | 
| 648 | 
            +
                def nakayoshi_gc
         | 
| 649 | 
            +
                  return unless @options[:nakayoshi_fork]
         | 
| 650 | 
            +
                  log "! Promoting existing objects to old generation..."
         | 
| 651 | 
            +
                  4.times { GC.start(full_mark: false) }
         | 
| 652 | 
            +
                  if GC.respond_to?(:compact)
         | 
| 653 | 
            +
                    log "! Compacting..."
         | 
| 654 | 
            +
                    GC.compact
         | 
| 655 | 
            +
                  end
         | 
| 656 | 
            +
                  log "! Friendly fork preparation complete."
         | 
| 657 | 
            +
                end
         | 
| 553 658 | 
             
              end
         | 
| 554 659 | 
             
            end
         | 
    
        data/lib/puma/commonlogger.rb
    CHANGED
    
    | 
            File without changes
         | 
    
        data/lib/puma/configuration.rb
    CHANGED
    
    | @@ -54,9 +54,7 @@ module Puma | |
| 54 54 | 
             
                attr_reader :user_options, :file_options, :default_options
         | 
| 55 55 |  | 
| 56 56 | 
             
                def [](key)
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
                  return file_options[key]    if file_options.key?(key)
         | 
| 59 | 
            -
                  return default_options[key] if default_options.key?(key)
         | 
| 57 | 
            +
                  fetch(key)
         | 
| 60 58 | 
             
                end
         | 
| 61 59 |  | 
| 62 60 | 
             
                def []=(key, value)
         | 
| @@ -64,7 +62,11 @@ module Puma | |
| 64 62 | 
             
                end
         | 
| 65 63 |  | 
| 66 64 | 
             
                def fetch(key, default_value = nil)
         | 
| 67 | 
            -
                   | 
| 65 | 
            +
                  return user_options[key]    if user_options.key?(key)
         | 
| 66 | 
            +
                  return file_options[key]    if file_options.key?(key)
         | 
| 67 | 
            +
                  return default_options[key] if default_options.key?(key)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  default_value
         | 
| 68 70 | 
             
                end
         | 
| 69 71 |  | 
| 70 72 | 
             
                def all_of(key)
         | 
| @@ -106,7 +108,7 @@ module Puma | |
| 106 108 | 
             
              #
         | 
| 107 109 | 
             
              # It also handles loading plugins.
         | 
| 108 110 | 
             
              #
         | 
| 109 | 
            -
              # > Note: `:port` and `:host` are not valid keys. By  | 
| 111 | 
            +
              # > Note: `:port` and `:host` are not valid keys. By the time they make it to the
         | 
| 110 112 | 
             
              #   configuration options they are expected to be incorporated into a `:binds` key.
         | 
| 111 113 | 
             
              #   Under the hood the DSL maps `port` and `host` calls to `:binds`
         | 
| 112 114 | 
             
              #
         | 
| @@ -137,6 +139,10 @@ module Puma | |
| 137 139 | 
             
                  @file_dsl    = DSL.new(@options.file_options, self)
         | 
| 138 140 | 
             
                  @default_dsl = DSL.new(@options.default_options, self)
         | 
| 139 141 |  | 
| 142 | 
            +
                  if !@options[:prune_bundler]
         | 
| 143 | 
            +
                    default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
             | 
| 140 146 | 
             
                  if block
         | 
| 141 147 | 
             
                    configure(&block)
         | 
| 142 148 | 
             
                  end
         | 
| @@ -167,22 +173,25 @@ module Puma | |
| 167 173 | 
             
                  self
         | 
| 168 174 | 
             
                end
         | 
| 169 175 |  | 
| 176 | 
            +
                def default_max_threads
         | 
| 177 | 
            +
                  Puma.mri? ? 5 : 16
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
             | 
| 170 180 | 
             
                def puma_default_options
         | 
| 171 181 | 
             
                  {
         | 
| 172 | 
            -
                    :min_threads => 0,
         | 
| 173 | 
            -
                    :max_threads =>  | 
| 182 | 
            +
                    :min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
         | 
| 183 | 
            +
                    :max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
         | 
| 174 184 | 
             
                    :log_requests => false,
         | 
| 175 185 | 
             
                    :debug => false,
         | 
| 176 186 | 
             
                    :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
         | 
| 177 | 
            -
                    :workers => 0,
         | 
| 178 | 
            -
                    :daemon => false,
         | 
| 187 | 
            +
                    :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
         | 
| 179 188 | 
             
                    :mode => :http,
         | 
| 180 189 | 
             
                    :worker_timeout => DefaultWorkerTimeout,
         | 
| 181 190 | 
             
                    :worker_boot_timeout => DefaultWorkerTimeout,
         | 
| 182 191 | 
             
                    :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
         | 
| 183 192 | 
             
                    :remote_address => :socket,
         | 
| 184 193 | 
             
                    :tag => method(:infer_tag),
         | 
| 185 | 
            -
                    :environment => -> { ENV['RACK_ENV'] || "development" },
         | 
| 194 | 
            +
                    :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
         | 
| 186 195 | 
             
                    :rackup => DefaultRackup,
         | 
| 187 196 | 
             
                    :logger => STDOUT,
         | 
| 188 197 | 
             
                    :persistent_timeout => Const::PERSISTENT_TIMEOUT,
         | 
| @@ -245,14 +254,6 @@ module Puma | |
| 245 254 | 
             
                def app
         | 
| 246 255 | 
             
                  found = options[:app] || load_rackup
         | 
| 247 256 |  | 
| 248 | 
            -
                  if @options[:mode] == :tcp
         | 
| 249 | 
            -
                    require 'puma/tcp_logger'
         | 
| 250 | 
            -
             | 
| 251 | 
            -
                    logger = @options[:logger]
         | 
| 252 | 
            -
                    quiet = !@options[:log_requests]
         | 
| 253 | 
            -
                    return TCPLogger.new(logger, found, quiet)
         | 
| 254 | 
            -
                  end
         | 
| 255 | 
            -
             | 
| 256 257 | 
             
                  if @options[:log_requests]
         | 
| 257 258 | 
             
                    require 'puma/commonlogger'
         | 
| 258 259 | 
             
                    logger = @options[:logger]
         | 
| @@ -275,8 +276,15 @@ module Puma | |
| 275 276 | 
             
                  @plugins.create name
         | 
| 276 277 | 
             
                end
         | 
| 277 278 |  | 
| 278 | 
            -
                def run_hooks(key, arg)
         | 
| 279 | 
            -
                  @options.all_of(key).each  | 
| 279 | 
            +
                def run_hooks(key, arg, events)
         | 
| 280 | 
            +
                  @options.all_of(key).each do |b|
         | 
| 281 | 
            +
                    begin
         | 
| 282 | 
            +
                      b.call arg
         | 
| 283 | 
            +
                    rescue => e
         | 
| 284 | 
            +
                      events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
         | 
| 285 | 
            +
                      events.debug e.backtrace.join("\n")
         | 
| 286 | 
            +
                    end
         | 
| 287 | 
            +
                  end
         | 
| 280 288 | 
             
                end
         | 
| 281 289 |  | 
| 282 290 | 
             
                def self.temp_path
         | 
| @@ -332,29 +340,9 @@ module Puma | |
| 332 340 | 
             
                end
         | 
| 333 341 |  | 
| 334 342 | 
             
                def self.random_token
         | 
| 335 | 
            -
                   | 
| 336 | 
            -
                    require 'openssl'
         | 
| 337 | 
            -
                  rescue LoadError
         | 
| 338 | 
            -
                  end
         | 
| 339 | 
            -
             | 
| 340 | 
            -
                  count = 16
         | 
| 341 | 
            -
             | 
| 342 | 
            -
                  bytes = nil
         | 
| 343 | 
            -
             | 
| 344 | 
            -
                  if defined? OpenSSL::Random
         | 
| 345 | 
            -
                    bytes = OpenSSL::Random.random_bytes(count)
         | 
| 346 | 
            -
                  elsif File.exist?("/dev/urandom")
         | 
| 347 | 
            -
                    File.open('/dev/urandom') { |f| bytes = f.read(count) }
         | 
| 348 | 
            -
                  end
         | 
| 349 | 
            -
             | 
| 350 | 
            -
                  if bytes
         | 
| 351 | 
            -
                    token = "".dup
         | 
| 352 | 
            -
                    bytes.each_byte { |b| token << b.to_s(16) }
         | 
| 353 | 
            -
                  else
         | 
| 354 | 
            -
                    token = (0..count).to_a.map { rand(255).to_s(16) }.join
         | 
| 355 | 
            -
                  end
         | 
| 343 | 
            +
                  require 'securerandom' unless defined?(SecureRandom)
         | 
| 356 344 |  | 
| 357 | 
            -
                   | 
| 345 | 
            +
                  SecureRandom.hex(16)
         | 
| 358 346 | 
             
                end
         | 
| 359 347 | 
             
              end
         | 
| 360 348 | 
             
            end
         | 
    
        data/lib/puma/const.rb
    CHANGED
    
    | @@ -76,7 +76,7 @@ module Puma | |
| 76 76 | 
             
                508 => 'Loop Detected',
         | 
| 77 77 | 
             
                510 => 'Not Extended',
         | 
| 78 78 | 
             
                511 => 'Network Authentication Required'
         | 
| 79 | 
            -
              } | 
| 79 | 
            +
              }
         | 
| 80 80 |  | 
| 81 81 | 
             
              # For some HTTP status codes the client only expects headers.
         | 
| 82 82 | 
             
              #
         | 
| @@ -85,7 +85,7 @@ module Puma | |
| 85 85 | 
             
                204 => true,
         | 
| 86 86 | 
             
                205 => true,
         | 
| 87 87 | 
             
                304 => true
         | 
| 88 | 
            -
              } | 
| 88 | 
            +
              }
         | 
| 89 89 |  | 
| 90 90 | 
             
              # Frequently used constants when constructing requests or responses.  Many times
         | 
| 91 91 | 
             
              # the constant just refers to a string with the same contents.  Using these constants
         | 
| @@ -100,8 +100,8 @@ module Puma | |
| 100 100 | 
             
              # too taxing on performance.
         | 
| 101 101 | 
             
              module Const
         | 
| 102 102 |  | 
| 103 | 
            -
                PUMA_VERSION = VERSION = " | 
| 104 | 
            -
                CODE_NAME = " | 
| 103 | 
            +
                PUMA_VERSION = VERSION = "5.0.0.beta1".freeze
         | 
| 104 | 
            +
                CODE_NAME = "Spoony Bard".freeze
         | 
| 105 105 | 
             
                PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
         | 
| 106 106 |  | 
| 107 107 | 
             
                FAST_TRACK_KA_TIMEOUT = 0.2
         | 
| @@ -144,11 +144,9 @@ module Puma | |
| 144 144 | 
             
                  408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
         | 
| 145 145 | 
             
                  # Indicate that there was an internal error, obviously.
         | 
| 146 146 | 
             
                  500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
         | 
| 147 | 
            -
                  # Incorrect or invalid header value
         | 
| 148 | 
            -
                  501 => "HTTP/1.1 501 Not Implemented\r\n\r\n".freeze,
         | 
| 149 147 | 
             
                  # A common header for indicating the server is too busy.  Not used yet.
         | 
| 150 148 | 
             
                  503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
         | 
| 151 | 
            -
                } | 
| 149 | 
            +
                }
         | 
| 152 150 |  | 
| 153 151 | 
             
                # The basic max request size we'll try to read.
         | 
| 154 152 | 
             
                CHUNK_SIZE = 16 * 1024
         | 
| @@ -177,7 +175,6 @@ module Puma | |
| 177 175 | 
             
                PORT_443 = "443".freeze
         | 
| 178 176 | 
             
                LOCALHOST = "localhost".freeze
         | 
| 179 177 | 
             
                LOCALHOST_IP = "127.0.0.1".freeze
         | 
| 180 | 
            -
                LOCALHOST_ADDR = "127.0.0.1:0".freeze
         | 
| 181 178 |  | 
| 182 179 | 
             
                SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
         | 
| 183 180 | 
             
                HTTP_11 = "HTTP/1.1".freeze
         |