puma 4.3.8-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 -21
 - data/LICENSE +23 -20
 - data/README.md +17 -11
 - data/docs/deployment.md +3 -1
 - data/docs/fork_worker.md +31 -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/signals.md +1 -0
 - data/docs/systemd.md +1 -63
 - data/ext/puma_http11/PumaHttp11Service.java +2 -4
 - data/ext/puma_http11/extconf.rb +3 -2
 - data/ext/puma_http11/http11_parser.c +65 -67
 - data/ext/puma_http11/http11_parser.rl +1 -3
 - data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
 - data/ext/puma_http11/puma_http11.c +2 -38
 - data/lib/puma.rb +4 -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 +35 -32
 - data/lib/puma/cluster.rb +179 -74
 - data/lib/puma/configuration.rb +30 -42
 - data/lib/puma/const.rb +2 -3
 - 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/io_buffer.rb +9 -2
 - data/lib/puma/jruby_restart.rb +0 -58
 - data/lib/puma/launcher.rb +41 -29
 - data/lib/puma/minissl.rb +13 -8
 - data/lib/puma/null_io.rb +1 -1
 - 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/reactor.rb +6 -1
 - data/lib/puma/runner.rb +5 -34
 - data/lib/puma/server.rb +70 -190
 - 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/rack/handler/puma.rb +1 -3
 - data/tools/{docker/Dockerfile → Dockerfile} +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
         
     |