puma 5.2.2 → 6.3.0
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 +483 -4
 - data/README.md +101 -20
 - data/bin/puma-wild +1 -1
 - data/docs/architecture.md +50 -16
 - data/docs/compile_options.md +38 -2
 - data/docs/deployment.md +53 -67
 - data/docs/fork_worker.md +1 -3
 - data/docs/jungle/rc.d/README.md +1 -1
 - data/docs/kubernetes.md +1 -1
 - data/docs/nginx.md +1 -1
 - data/docs/plugins.md +15 -15
 - data/docs/rails_dev_mode.md +2 -3
 - data/docs/restart.md +7 -7
 - data/docs/signals.md +11 -10
 - data/docs/stats.md +8 -8
 - data/docs/systemd.md +65 -69
 - data/docs/testing_benchmarks_local_files.md +150 -0
 - data/docs/testing_test_rackup_ci_files.md +36 -0
 - data/ext/puma_http11/extconf.rb +44 -13
 - data/ext/puma_http11/http11_parser.c +24 -11
 - data/ext/puma_http11/http11_parser.h +2 -2
 - data/ext/puma_http11/http11_parser.java.rl +2 -2
 - data/ext/puma_http11/http11_parser.rl +2 -2
 - data/ext/puma_http11/http11_parser_common.rl +3 -3
 - data/ext/puma_http11/mini_ssl.c +150 -23
 - data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
 - data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
 - data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
 - data/ext/puma_http11/puma_http11.c +18 -10
 - data/lib/puma/app/status.rb +10 -7
 - data/lib/puma/binder.rb +112 -62
 - data/lib/puma/cli.rb +24 -20
 - data/lib/puma/client.rb +162 -36
 - data/lib/puma/cluster/worker.rb +31 -27
 - data/lib/puma/cluster/worker_handle.rb +12 -1
 - data/lib/puma/cluster.rb +102 -61
 - data/lib/puma/commonlogger.rb +21 -14
 - data/lib/puma/configuration.rb +78 -54
 - data/lib/puma/const.rb +135 -97
 - data/lib/puma/control_cli.rb +25 -20
 - data/lib/puma/detect.rb +12 -2
 - data/lib/puma/dsl.rb +308 -58
 - data/lib/puma/error_logger.rb +20 -11
 - data/lib/puma/events.rb +6 -126
 - data/lib/puma/io_buffer.rb +39 -4
 - data/lib/puma/jruby_restart.rb +2 -1
 - data/lib/puma/{json.rb → json_serialization.rb} +1 -1
 - data/lib/puma/launcher/bundle_pruner.rb +104 -0
 - data/lib/puma/launcher.rb +114 -173
 - data/lib/puma/log_writer.rb +147 -0
 - data/lib/puma/minissl/context_builder.rb +30 -16
 - data/lib/puma/minissl.rb +132 -38
 - data/lib/puma/null_io.rb +5 -0
 - data/lib/puma/plugin/systemd.rb +90 -0
 - data/lib/puma/plugin/tmp_restart.rb +1 -1
 - data/lib/puma/plugin.rb +2 -2
 - data/lib/puma/rack/builder.rb +7 -7
 - data/lib/puma/rack_default.rb +19 -4
 - data/lib/puma/reactor.rb +19 -10
 - data/lib/puma/request.rb +373 -153
 - data/lib/puma/runner.rb +74 -28
 - data/lib/puma/sd_notify.rb +149 -0
 - data/lib/puma/server.rb +127 -136
 - data/lib/puma/single.rb +13 -11
 - data/lib/puma/state_file.rb +39 -7
 - data/lib/puma/thread_pool.rb +33 -26
 - data/lib/puma/util.rb +20 -15
 - data/lib/puma.rb +28 -11
 - data/lib/rack/handler/puma.rb +113 -86
 - data/tools/Dockerfile +1 -1
 - metadata +15 -10
 - data/lib/puma/queue_close.rb +0 -26
 - data/lib/puma/systemd.rb +0 -46
 
    
        data/lib/puma/cluster.rb
    CHANGED
    
    | 
         @@ -1,12 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            require 'time'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'runner'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'util'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'plugin'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'cluster/worker_handle'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'cluster/worker'
         
     | 
| 
       10 
8 
     | 
    
         | 
| 
       11 
9 
     | 
    
         
             
            module Puma
         
     | 
| 
       12 
10 
     | 
    
         
             
              # This class is instantiated by the `Puma::Launcher` and used
         
     | 
| 
         @@ -17,8 +15,8 @@ module Puma 
     | 
|
| 
       17 
15 
     | 
    
         
             
              # via the `spawn_workers` method call. Each worker will have it's own
         
     | 
| 
       18 
16 
     | 
    
         
             
              # instance of a `Puma::Server`.
         
     | 
| 
       19 
17 
     | 
    
         
             
              class Cluster < Runner
         
     | 
| 
       20 
     | 
    
         
            -
                def initialize( 
     | 
| 
       21 
     | 
    
         
            -
                  super 
     | 
| 
      
 18 
     | 
    
         
            +
                def initialize(launcher)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  super(launcher)
         
     | 
| 
       22 
20 
     | 
    
         | 
| 
       23 
21 
     | 
    
         
             
                  @phase = 0
         
     | 
| 
       24 
22 
     | 
    
         
             
                  @workers = []
         
     | 
| 
         @@ -27,6 +25,10 @@ module Puma 
     | 
|
| 
       27 
25 
     | 
    
         
             
                  @phased_restart = false
         
     | 
| 
       28 
26 
     | 
    
         
             
                end
         
     | 
| 
       29 
27 
     | 
    
         | 
| 
      
 28 
     | 
    
         
            +
                # Returns the list of cluster worker handles.
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @return [Array<Puma::Cluster::WorkerHandle>]
         
     | 
| 
      
 30 
     | 
    
         
            +
                attr_reader :workers
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       30 
32 
     | 
    
         
             
                def stop_workers
         
     | 
| 
       31 
33 
     | 
    
         
             
                  log "- Gracefully shutting down workers..."
         
     | 
| 
       32 
34 
     | 
    
         
             
                  @workers.each { |x| x.term }
         
     | 
| 
         @@ -43,6 +45,7 @@ module Puma 
     | 
|
| 
       43 
45 
     | 
    
         
             
                end
         
     | 
| 
       44 
46 
     | 
    
         | 
| 
       45 
47 
     | 
    
         
             
                def start_phased_restart
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @events.fire_on_restart!
         
     | 
| 
       46 
49 
     | 
    
         
             
                  @phase += 1
         
     | 
| 
       47 
50 
     | 
    
         
             
                  log "- Starting phased worker restart, phase: #{@phase}"
         
     | 
| 
       48 
51 
     | 
    
         | 
| 
         @@ -91,7 +94,7 @@ module Puma 
     | 
|
| 
       91 
94 
     | 
    
         | 
| 
       92 
95 
     | 
    
         
             
                # @version 5.0.0
         
     | 
| 
       93 
96 
     | 
    
         
             
                def spawn_worker(idx, master)
         
     | 
| 
       94 
     | 
    
         
            -
                  @ 
     | 
| 
      
 97 
     | 
    
         
            +
                  @config.run_hooks(:before_worker_fork, idx, @log_writer)
         
     | 
| 
       95 
98 
     | 
    
         | 
| 
       96 
99 
     | 
    
         
             
                  pid = fork { worker(idx, master) }
         
     | 
| 
       97 
100 
     | 
    
         
             
                  if !pid
         
     | 
| 
         @@ -100,31 +103,49 @@ module Puma 
     | 
|
| 
       100 
103 
     | 
    
         
             
                    exit! 1
         
     | 
| 
       101 
104 
     | 
    
         
             
                  end
         
     | 
| 
       102 
105 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                  @ 
     | 
| 
      
 106 
     | 
    
         
            +
                  @config.run_hooks(:after_worker_fork, idx, @log_writer)
         
     | 
| 
       104 
107 
     | 
    
         
             
                  pid
         
     | 
| 
       105 
108 
     | 
    
         
             
                end
         
     | 
| 
       106 
109 
     | 
    
         | 
| 
       107 
110 
     | 
    
         
             
                def cull_workers
         
     | 
| 
       108 
111 
     | 
    
         
             
                  diff = @workers.size - @options[:workers]
         
     | 
| 
       109 
112 
     | 
    
         
             
                  return if diff < 1
         
     | 
| 
      
 113 
     | 
    
         
            +
                  debug "Culling #{diff} workers"
         
     | 
| 
       110 
114 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                   
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
                  workers_to_cull = @workers[-diff,diff]
         
     | 
| 
       114 
     | 
    
         
            -
                  debug "Workers to cull: #{workers_to_cull.inspect}"
         
     | 
| 
      
 115 
     | 
    
         
            +
                  workers = workers_to_cull(diff)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  debug "Workers to cull: #{workers.inspect}"
         
     | 
| 
       115 
117 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
                   
     | 
| 
      
 118 
     | 
    
         
            +
                  workers.each do |worker|
         
     | 
| 
       117 
119 
     | 
    
         
             
                    log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
         
     | 
| 
       118 
120 
     | 
    
         
             
                    worker.term
         
     | 
| 
       119 
121 
     | 
    
         
             
                  end
         
     | 
| 
       120 
122 
     | 
    
         
             
                end
         
     | 
| 
       121 
123 
     | 
    
         | 
| 
      
 124 
     | 
    
         
            +
                def workers_to_cull(diff)
         
     | 
| 
      
 125 
     | 
    
         
            +
                  workers = @workers.sort_by(&:started_at)
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                  # In fork_worker mode, worker 0 acts as our master process.
         
     | 
| 
      
 128 
     | 
    
         
            +
                  # We should avoid culling it to preserve copy-on-write memory gains.
         
     | 
| 
      
 129 
     | 
    
         
            +
                  workers.reject! { |w| w.index == 0 } if @options[:fork_worker]
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  workers[cull_start_index(diff), diff]
         
     | 
| 
      
 132 
     | 
    
         
            +
                end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                def cull_start_index(diff)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  case @options[:worker_culling_strategy]
         
     | 
| 
      
 136 
     | 
    
         
            +
                  when :oldest
         
     | 
| 
      
 137 
     | 
    
         
            +
                    0
         
     | 
| 
      
 138 
     | 
    
         
            +
                  else # :youngest
         
     | 
| 
      
 139 
     | 
    
         
            +
                    -diff
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
                end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
       122 
143 
     | 
    
         
             
                # @!attribute [r] next_worker_index
         
     | 
| 
       123 
144 
     | 
    
         
             
                def next_worker_index
         
     | 
| 
       124 
     | 
    
         
            -
                   
     | 
| 
       125 
     | 
    
         
            -
                   
     | 
| 
       126 
     | 
    
         
            -
                   
     | 
| 
       127 
     | 
    
         
            -
                   
     | 
| 
      
 145 
     | 
    
         
            +
                  occupied_positions = @workers.map(&:index)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  idx = 0
         
     | 
| 
      
 147 
     | 
    
         
            +
                  idx += 1 until !occupied_positions.include?(idx)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  idx
         
     | 
| 
       128 
149 
     | 
    
         
             
                end
         
     | 
| 
       129 
150 
     | 
    
         | 
| 
       130 
151 
     | 
    
         
             
                def all_workers_booted?
         
     | 
| 
         @@ -134,7 +155,7 @@ module Puma 
     | 
|
| 
       134 
155 
     | 
    
         
             
                def check_workers
         
     | 
| 
       135 
156 
     | 
    
         
             
                  return if @next_check >= Time.now
         
     | 
| 
       136 
157 
     | 
    
         | 
| 
       137 
     | 
    
         
            -
                  @next_check = Time.now +  
     | 
| 
      
 158 
     | 
    
         
            +
                  @next_check = Time.now + @options[:worker_check_interval]
         
     | 
| 
       138 
159 
     | 
    
         | 
| 
       139 
160 
     | 
    
         
             
                  timeout_workers
         
     | 
| 
       140 
161 
     | 
    
         
             
                  wait_workers
         
     | 
| 
         @@ -157,20 +178,10 @@ module Puma 
     | 
|
| 
       157 
178 
     | 
    
         
             
                    end
         
     | 
| 
       158 
179 
     | 
    
         
             
                  end
         
     | 
| 
       159 
180 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
                   
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
                    @next_check
         
     | 
| 
       163 
     | 
    
         
            -
                  ].compact.min
         
     | 
| 
       164 
     | 
    
         
            -
                end
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                def wakeup!
         
     | 
| 
       167 
     | 
    
         
            -
                  return unless @wakeup
         
     | 
| 
      
 181 
     | 
    
         
            +
                  t = @workers.reject(&:term?)
         
     | 
| 
      
 182 
     | 
    
         
            +
                  t.map!(&:ping_timeout)
         
     | 
| 
       168 
183 
     | 
    
         | 
| 
       169 
     | 
    
         
            -
                   
     | 
| 
       170 
     | 
    
         
            -
                    @wakeup.write "!" unless @wakeup.closed?
         
     | 
| 
       171 
     | 
    
         
            -
                  rescue SystemCallError, IOError
         
     | 
| 
       172 
     | 
    
         
            -
                    Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
         
     | 
| 
       173 
     | 
    
         
            -
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @next_check = [t.min, @next_check].compact.min
         
     | 
| 
       174 
185 
     | 
    
         
             
                end
         
     | 
| 
       175 
186 
     | 
    
         | 
| 
       176 
187 
     | 
    
         
             
                def worker(index, master)
         
     | 
| 
         @@ -200,8 +211,8 @@ module Puma 
     | 
|
| 
       200 
211 
     | 
    
         
             
                  stop
         
     | 
| 
       201 
212 
     | 
    
         
             
                end
         
     | 
| 
       202 
213 
     | 
    
         | 
| 
       203 
     | 
    
         
            -
                def phased_restart
         
     | 
| 
       204 
     | 
    
         
            -
                  return false if @options[:preload_app]
         
     | 
| 
      
 214 
     | 
    
         
            +
                def phased_restart(refork = false)
         
     | 
| 
      
 215 
     | 
    
         
            +
                  return false if @options[:preload_app] && !refork
         
     | 
| 
       205 
216 
     | 
    
         | 
| 
       206 
217 
     | 
    
         
             
                  @phased_restart = true
         
     | 
| 
       207 
218 
     | 
    
         
             
                  wakeup!
         
     | 
| 
         @@ -217,7 +228,7 @@ module Puma 
     | 
|
| 
       217 
228 
     | 
    
         
             
                def stop_blocked
         
     | 
| 
       218 
229 
     | 
    
         
             
                  @status = :stop if @status == :run
         
     | 
| 
       219 
230 
     | 
    
         
             
                  wakeup!
         
     | 
| 
       220 
     | 
    
         
            -
                  @control 
     | 
| 
      
 231 
     | 
    
         
            +
                  @control&.stop true
         
     | 
| 
       221 
232 
     | 
    
         
             
                  Process.waitall
         
     | 
| 
       222 
233 
     | 
    
         
             
                end
         
     | 
| 
       223 
234 
     | 
    
         | 
| 
         @@ -239,24 +250,24 @@ module Puma 
     | 
|
| 
       239 
250 
     | 
    
         
             
                  old_worker_count = @workers.count { |w| w.phase != @phase }
         
     | 
| 
       240 
251 
     | 
    
         
             
                  worker_status = @workers.map do |w|
         
     | 
| 
       241 
252 
     | 
    
         
             
                    {
         
     | 
| 
       242 
     | 
    
         
            -
                      started_at: w.started_at 
     | 
| 
      
 253 
     | 
    
         
            +
                      started_at: utc_iso8601(w.started_at),
         
     | 
| 
       243 
254 
     | 
    
         
             
                      pid: w.pid,
         
     | 
| 
       244 
255 
     | 
    
         
             
                      index: w.index,
         
     | 
| 
       245 
256 
     | 
    
         
             
                      phase: w.phase,
         
     | 
| 
       246 
257 
     | 
    
         
             
                      booted: w.booted?,
         
     | 
| 
       247 
     | 
    
         
            -
                      last_checkin: w.last_checkin 
     | 
| 
      
 258 
     | 
    
         
            +
                      last_checkin: utc_iso8601(w.last_checkin),
         
     | 
| 
       248 
259 
     | 
    
         
             
                      last_status: w.last_status,
         
     | 
| 
       249 
260 
     | 
    
         
             
                    }
         
     | 
| 
       250 
261 
     | 
    
         
             
                  end
         
     | 
| 
       251 
262 
     | 
    
         | 
| 
       252 
263 
     | 
    
         
             
                  {
         
     | 
| 
       253 
     | 
    
         
            -
                    started_at: @started_at 
     | 
| 
      
 264 
     | 
    
         
            +
                    started_at: utc_iso8601(@started_at),
         
     | 
| 
       254 
265 
     | 
    
         
             
                    workers: @workers.size,
         
     | 
| 
       255 
266 
     | 
    
         
             
                    phase: @phase,
         
     | 
| 
       256 
267 
     | 
    
         
             
                    booted_workers: worker_status.count { |w| w[:booted] },
         
     | 
| 
       257 
268 
     | 
    
         
             
                    old_workers: old_worker_count,
         
     | 
| 
       258 
269 
     | 
    
         
             
                    worker_status: worker_status,
         
     | 
| 
       259 
     | 
    
         
            -
                  }
         
     | 
| 
      
 270 
     | 
    
         
            +
                  }.merge(super)
         
     | 
| 
       260 
271 
     | 
    
         
             
                end
         
     | 
| 
       261 
272 
     | 
    
         | 
| 
       262 
273 
     | 
    
         
             
                def preload?
         
     | 
| 
         @@ -268,7 +279,7 @@ module Puma 
     | 
|
| 
       268 
279 
     | 
    
         
             
                  if (worker = @workers.find { |w| w.index == 0 })
         
     | 
| 
       269 
280 
     | 
    
         
             
                    worker.phase += 1
         
     | 
| 
       270 
281 
     | 
    
         
             
                  end
         
     | 
| 
       271 
     | 
    
         
            -
                  phased_restart
         
     | 
| 
      
 282 
     | 
    
         
            +
                  phased_restart(true)
         
     | 
| 
       272 
283 
     | 
    
         
             
                end
         
     | 
| 
       273 
284 
     | 
    
         | 
| 
       274 
285 
     | 
    
         
             
                # We do this in a separate method to keep the lambda scope
         
     | 
| 
         @@ -281,7 +292,7 @@ module Puma 
     | 
|
| 
       281 
292 
     | 
    
         | 
| 
       282 
293 
     | 
    
         
             
                    # Auto-fork after the specified number of requests.
         
     | 
| 
       283 
294 
     | 
    
         
             
                    if (fork_requests = @options[:fork_worker].to_i) > 0
         
     | 
| 
       284 
     | 
    
         
            -
                      @ 
     | 
| 
      
 295 
     | 
    
         
            +
                      @events.register(:ping!) do |w|
         
     | 
| 
       285 
296 
     | 
    
         
             
                        fork_worker! if w.index == 0 &&
         
     | 
| 
       286 
297 
     | 
    
         
             
                          w.phase == 0 &&
         
     | 
| 
       287 
298 
     | 
    
         
             
                          w.last_status[:requests_count] >= fork_requests
         
     | 
| 
         @@ -317,7 +328,7 @@ module Puma 
     | 
|
| 
       317 
328 
     | 
    
         | 
| 
       318 
329 
     | 
    
         
             
                      stop_workers
         
     | 
| 
       319 
330 
     | 
    
         
             
                      stop
         
     | 
| 
       320 
     | 
    
         
            -
             
     | 
| 
      
 331 
     | 
    
         
            +
                      @events.fire_on_stopped!
         
     | 
| 
       321 
332 
     | 
    
         
             
                      raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
         
     | 
| 
       322 
333 
     | 
    
         
             
                      exit 0 # Clean exit, workers were stopped
         
     | 
| 
       323 
334 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -332,16 +343,22 @@ module Puma 
     | 
|
| 
       332 
343 
     | 
    
         
             
                  # This is aligned with the output from Runner, see Runner#output_header
         
     | 
| 
       333 
344 
     | 
    
         
             
                  log "*      Workers: #{@options[:workers]}"
         
     | 
| 
       334 
345 
     | 
    
         | 
| 
       335 
     | 
    
         
            -
                  # Threads explicitly marked as fork safe will be ignored.
         
     | 
| 
       336 
     | 
    
         
            -
                  # Used in Rails, but may be used by anyone.
         
     | 
| 
       337 
     | 
    
         
            -
                  before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
         
     | 
| 
       338 
     | 
    
         
            -
             
     | 
| 
       339 
346 
     | 
    
         
             
                  if preload?
         
     | 
| 
      
 347 
     | 
    
         
            +
                    # Threads explicitly marked as fork safe will be ignored. Used in Rails,
         
     | 
| 
      
 348 
     | 
    
         
            +
                    # but may be used by anyone. Note that we need to explicit
         
     | 
| 
      
 349 
     | 
    
         
            +
                    # Process::Waiter check here because there's a bug in Ruby 2.6 and below
         
     | 
| 
      
 350 
     | 
    
         
            +
                    # where calling thread_variable_get on a Process::Waiter will segfault.
         
     | 
| 
      
 351 
     | 
    
         
            +
                    # We can drop that clause once those versions of Ruby are no longer
         
     | 
| 
      
 352 
     | 
    
         
            +
                    # supported.
         
     | 
| 
      
 353 
     | 
    
         
            +
                    fork_safe = ->(t) { !t.is_a?(Process::Waiter) && t.thread_variable_get(:fork_safe) }
         
     | 
| 
      
 354 
     | 
    
         
            +
             
     | 
| 
      
 355 
     | 
    
         
            +
                    before = Thread.list.reject(&fork_safe)
         
     | 
| 
      
 356 
     | 
    
         
            +
             
     | 
| 
       340 
357 
     | 
    
         
             
                    log "*     Restarts: (\u2714) hot (\u2716) phased"
         
     | 
| 
       341 
358 
     | 
    
         
             
                    log "* Preloading application"
         
     | 
| 
       342 
359 
     | 
    
         
             
                    load_and_bind
         
     | 
| 
       343 
360 
     | 
    
         | 
| 
       344 
     | 
    
         
            -
                    after = Thread.list.reject 
     | 
| 
      
 361 
     | 
    
         
            +
                    after = Thread.list.reject(&fork_safe)
         
     | 
| 
       345 
362 
     | 
    
         | 
| 
       346 
363 
     | 
    
         
             
                    if after.size > before.size
         
     | 
| 
       347 
364 
     | 
    
         
             
                      threads = (after - before)
         
     | 
| 
         @@ -357,12 +374,12 @@ module Puma 
     | 
|
| 
       357 
374 
     | 
    
         
             
                  else
         
     | 
| 
       358 
375 
     | 
    
         
             
                    log "*     Restarts: (\u2714) hot (\u2714) phased"
         
     | 
| 
       359 
376 
     | 
    
         | 
| 
       360 
     | 
    
         
            -
                    unless @ 
     | 
| 
      
 377 
     | 
    
         
            +
                    unless @config.app_configured?
         
     | 
| 
       361 
378 
     | 
    
         
             
                      error "No application configured, nothing to run"
         
     | 
| 
       362 
379 
     | 
    
         
             
                      exit 1
         
     | 
| 
       363 
380 
     | 
    
         
             
                    end
         
     | 
| 
       364 
381 
     | 
    
         | 
| 
       365 
     | 
    
         
            -
                    @launcher.binder.parse @options[:binds] 
     | 
| 
      
 382 
     | 
    
         
            +
                    @launcher.binder.parse @options[:binds]
         
     | 
| 
       366 
383 
     | 
    
         
             
                  end
         
     | 
| 
       367 
384 
     | 
    
         | 
| 
       368 
385 
     | 
    
         
             
                  read, @wakeup = Puma::Util.pipe
         
     | 
| 
         @@ -382,6 +399,8 @@ module Puma 
     | 
|
| 
       382 
399 
     | 
    
         | 
| 
       383 
400 
     | 
    
         
             
                  log "Use Ctrl-C to stop"
         
     | 
| 
       384 
401 
     | 
    
         | 
| 
      
 402 
     | 
    
         
            +
                  single_worker_warning
         
     | 
| 
      
 403 
     | 
    
         
            +
             
     | 
| 
       385 
404 
     | 
    
         
             
                  redirect_io
         
     | 
| 
       386 
405 
     | 
    
         | 
| 
       387 
406 
     | 
    
         
             
                  Plugins.fire_background
         
     | 
| 
         @@ -392,8 +411,7 @@ module Puma 
     | 
|
| 
       392 
411 
     | 
    
         | 
| 
       393 
412 
     | 
    
         
             
                  @master_read, @worker_write = read, @wakeup
         
     | 
| 
       394 
413 
     | 
    
         | 
| 
       395 
     | 
    
         
            -
                  @ 
     | 
| 
       396 
     | 
    
         
            -
                  Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
         
     | 
| 
      
 414 
     | 
    
         
            +
                  @config.run_hooks(:before_fork, nil, @log_writer)
         
     | 
| 
       397 
415 
     | 
    
         | 
| 
       398 
416 
     | 
    
         
             
                  spawn_workers
         
     | 
| 
       399 
417 
     | 
    
         | 
| 
         @@ -403,19 +421,21 @@ module Puma 
     | 
|
| 
       403 
421 
     | 
    
         | 
| 
       404 
422 
     | 
    
         
             
                  begin
         
     | 
| 
       405 
423 
     | 
    
         
             
                    booted = false
         
     | 
| 
      
 424 
     | 
    
         
            +
                    in_phased_restart = false
         
     | 
| 
      
 425 
     | 
    
         
            +
                    workers_not_booted = @options[:workers]
         
     | 
| 
       406 
426 
     | 
    
         | 
| 
       407 
427 
     | 
    
         
             
                    while @status == :run
         
     | 
| 
       408 
428 
     | 
    
         
             
                      begin
         
     | 
| 
       409 
429 
     | 
    
         
             
                        if @phased_restart
         
     | 
| 
       410 
430 
     | 
    
         
             
                          start_phased_restart
         
     | 
| 
       411 
431 
     | 
    
         
             
                          @phased_restart = false
         
     | 
| 
      
 432 
     | 
    
         
            +
                          in_phased_restart = true
         
     | 
| 
      
 433 
     | 
    
         
            +
                          workers_not_booted = @options[:workers]
         
     | 
| 
       412 
434 
     | 
    
         
             
                        end
         
     | 
| 
       413 
435 
     | 
    
         | 
| 
       414 
436 
     | 
    
         
             
                        check_workers
         
     | 
| 
       415 
437 
     | 
    
         | 
| 
       416 
     | 
    
         
            -
                         
     | 
| 
       417 
     | 
    
         
            -
             
     | 
| 
       418 
     | 
    
         
            -
                        if res
         
     | 
| 
      
 438 
     | 
    
         
            +
                        if read.wait_readable([0, @next_check - Time.now].max)
         
     | 
| 
       419 
439 
     | 
    
         
             
                          req = read.read_nonblock(1)
         
     | 
| 
       420 
440 
     | 
    
         | 
| 
       421 
441 
     | 
    
         
             
                          @next_check = Time.now if req == "!"
         
     | 
| 
         @@ -434,18 +454,20 @@ module Puma 
     | 
|
| 
       434 
454 
     | 
    
         
             
                            case req
         
     | 
| 
       435 
455 
     | 
    
         
             
                            when "b"
         
     | 
| 
       436 
456 
     | 
    
         
             
                              w.boot!
         
     | 
| 
       437 
     | 
    
         
            -
                              log "- Worker #{w.index} (PID: #{pid}) booted, phase: #{w.phase}"
         
     | 
| 
      
 457 
     | 
    
         
            +
                              log "- Worker #{w.index} (PID: #{pid}) booted in #{w.uptime.round(2)}s, phase: #{w.phase}"
         
     | 
| 
       438 
458 
     | 
    
         
             
                              @next_check = Time.now
         
     | 
| 
      
 459 
     | 
    
         
            +
                              workers_not_booted -= 1
         
     | 
| 
       439 
460 
     | 
    
         
             
                            when "e"
         
     | 
| 
       440 
461 
     | 
    
         
             
                              # external term, see worker method, Signal.trap "SIGTERM"
         
     | 
| 
       441 
     | 
    
         
            -
                              w. 
     | 
| 
      
 462 
     | 
    
         
            +
                              w.term!
         
     | 
| 
       442 
463 
     | 
    
         
             
                            when "t"
         
     | 
| 
       443 
464 
     | 
    
         
             
                              w.term unless w.term?
         
     | 
| 
       444 
465 
     | 
    
         
             
                            when "p"
         
     | 
| 
       445 
466 
     | 
    
         
             
                              w.ping!(result.sub(/^\d+/,'').chomp)
         
     | 
| 
       446 
     | 
    
         
            -
                              @ 
     | 
| 
      
 467 
     | 
    
         
            +
                              @events.fire(:ping!, w)
         
     | 
| 
       447 
468 
     | 
    
         
             
                              if !booted && @workers.none? {|worker| worker.last_status.empty?}
         
     | 
| 
       448 
     | 
    
         
            -
                                @ 
     | 
| 
      
 469 
     | 
    
         
            +
                                @events.fire_on_booted!
         
     | 
| 
      
 470 
     | 
    
         
            +
                                debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
         
     | 
| 
       449 
471 
     | 
    
         
             
                                booted = true
         
     | 
| 
       450 
472 
     | 
    
         
             
                              end
         
     | 
| 
       451 
473 
     | 
    
         
             
                            end
         
     | 
| 
         @@ -453,6 +475,11 @@ module Puma 
     | 
|
| 
       453 
475 
     | 
    
         
             
                            log "! Out-of-sync worker list, no #{pid} worker"
         
     | 
| 
       454 
476 
     | 
    
         
             
                          end
         
     | 
| 
       455 
477 
     | 
    
         
             
                        end
         
     | 
| 
      
 478 
     | 
    
         
            +
                        if in_phased_restart && workers_not_booted.zero?
         
     | 
| 
      
 479 
     | 
    
         
            +
                          @events.fire_on_booted!
         
     | 
| 
      
 480 
     | 
    
         
            +
                          debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
         
     | 
| 
      
 481 
     | 
    
         
            +
                          in_phased_restart = false
         
     | 
| 
      
 482 
     | 
    
         
            +
                        end
         
     | 
| 
       456 
483 
     | 
    
         | 
| 
       457 
484 
     | 
    
         
             
                      rescue Interrupt
         
     | 
| 
       458 
485 
     | 
    
         
             
                        @status = :stop
         
     | 
| 
         @@ -470,6 +497,15 @@ module Puma 
     | 
|
| 
       470 
497 
     | 
    
         | 
| 
       471 
498 
     | 
    
         
             
                private
         
     | 
| 
       472 
499 
     | 
    
         | 
| 
      
 500 
     | 
    
         
            +
                def single_worker_warning
         
     | 
| 
      
 501 
     | 
    
         
            +
                  return if @options[:workers] != 1 || @options[:silence_single_worker_warning]
         
     | 
| 
      
 502 
     | 
    
         
            +
             
     | 
| 
      
 503 
     | 
    
         
            +
                  log "! WARNING: Detected running cluster mode with 1 worker."
         
     | 
| 
      
 504 
     | 
    
         
            +
                  log "! Running Puma in cluster mode with a single worker is often a misconfiguration."
         
     | 
| 
      
 505 
     | 
    
         
            +
                  log "! Consider running Puma in single-mode (workers = 0) in order to reduce memory overhead."
         
     | 
| 
      
 506 
     | 
    
         
            +
                  log "! Set the `silence_single_worker_warning` option to silence this warning message."
         
     | 
| 
      
 507 
     | 
    
         
            +
                end
         
     | 
| 
      
 508 
     | 
    
         
            +
             
     | 
| 
       473 
509 
     | 
    
         
             
                # loops thru @workers, removing workers that exited, and calling
         
     | 
| 
       474 
510 
     | 
    
         
             
                # `#term` if needed
         
     | 
| 
       475 
511 
     | 
    
         
             
                def wait_workers
         
     | 
| 
         @@ -499,7 +535,12 @@ module Puma 
     | 
|
| 
       499 
535 
     | 
    
         
             
                def timeout_workers
         
     | 
| 
       500 
536 
     | 
    
         
             
                  @workers.each do |w|
         
     | 
| 
       501 
537 
     | 
    
         
             
                    if !w.term? && w.ping_timeout <= Time.now
         
     | 
| 
       502 
     | 
    
         
            -
                       
     | 
| 
      
 538 
     | 
    
         
            +
                      details = if w.booted?
         
     | 
| 
      
 539 
     | 
    
         
            +
                                  "(worker failed to check in within #{@options[:worker_timeout]} seconds)"
         
     | 
| 
      
 540 
     | 
    
         
            +
                                else
         
     | 
| 
      
 541 
     | 
    
         
            +
                                  "(worker failed to boot within #{@options[:worker_boot_timeout]} seconds)"
         
     | 
| 
      
 542 
     | 
    
         
            +
                                end
         
     | 
| 
      
 543 
     | 
    
         
            +
                      log "! Terminating timed out worker #{details}: #{w.pid}"
         
     | 
| 
       503 
544 
     | 
    
         
             
                      w.kill
         
     | 
| 
       504 
545 
     | 
    
         
             
                    end
         
     | 
| 
       505 
546 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/puma/commonlogger.rb
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module Puma
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Rack::CommonLogger forwards every request to the given +app+, and
         
     | 
| 
       5 
5 
     | 
    
         
             
              # logs a line in the
         
     | 
| 
       6 
     | 
    
         
            -
              # {Apache common log format}[https://httpd.apache.org/docs/ 
     | 
| 
      
 6 
     | 
    
         
            +
              # {Apache common log format}[https://httpd.apache.org/docs/2.4/logs.html#common]
         
     | 
| 
       7 
7 
     | 
    
         
             
              # to the +logger+.
         
     | 
| 
       8 
8 
     | 
    
         
             
              #
         
     | 
| 
       9 
9 
     | 
    
         
             
              # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
         
     | 
| 
         @@ -16,7 +16,7 @@ module Puma 
     | 
|
| 
       16 
16 
     | 
    
         
             
              # (which is called without arguments in order to make the error appear for
         
     | 
| 
       17 
17 
     | 
    
         
             
              # sure)
         
     | 
| 
       18 
18 
     | 
    
         
             
              class CommonLogger
         
     | 
| 
       19 
     | 
    
         
            -
                # Common Log Format: https://httpd.apache.org/docs/ 
     | 
| 
      
 19 
     | 
    
         
            +
                # Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
         
     | 
| 
       20 
20 
     | 
    
         
             
                #
         
     | 
| 
       21 
21 
     | 
    
         
             
                #   lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
         
     | 
| 
       22 
22 
     | 
    
         
             
                #
         
     | 
| 
         @@ -25,10 +25,17 @@ module Puma 
     | 
|
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                 
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                 
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
                LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                CONTENT_LENGTH       = 'Content-Length' # should be lower case from app,
         
     | 
| 
      
 31 
     | 
    
         
            +
                                                        # Util::HeaderHash allows mixed
         
     | 
| 
      
 32 
     | 
    
         
            +
                HTTP_VERSION         = Const::HTTP_VERSION
         
     | 
| 
      
 33 
     | 
    
         
            +
                HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
         
     | 
| 
      
 34 
     | 
    
         
            +
                PATH_INFO            = Const::PATH_INFO
         
     | 
| 
      
 35 
     | 
    
         
            +
                QUERY_STRING         = Const::QUERY_STRING
         
     | 
| 
      
 36 
     | 
    
         
            +
                REMOTE_ADDR          = Const::REMOTE_ADDR
         
     | 
| 
      
 37 
     | 
    
         
            +
                REMOTE_USER          = 'REMOTE_USER'
         
     | 
| 
      
 38 
     | 
    
         
            +
                REQUEST_METHOD       = Const::REQUEST_METHOD
         
     | 
| 
       32 
39 
     | 
    
         | 
| 
       33 
40 
     | 
    
         
             
                def initialize(app, logger=nil)
         
     | 
| 
       34 
41 
     | 
    
         
             
                  @app = app
         
     | 
| 
         @@ -57,13 +64,13 @@ module Puma 
     | 
|
| 
       57 
64 
     | 
    
         
             
                  now = Time.now
         
     | 
| 
       58 
65 
     | 
    
         | 
| 
       59 
66 
     | 
    
         
             
                  msg = HIJACK_FORMAT % [
         
     | 
| 
       60 
     | 
    
         
            -
                    env[ 
     | 
| 
       61 
     | 
    
         
            -
                    env[ 
     | 
| 
       62 
     | 
    
         
            -
                    now.strftime( 
     | 
| 
      
 67 
     | 
    
         
            +
                    env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
         
     | 
| 
      
 68 
     | 
    
         
            +
                    env[REMOTE_USER] || "-",
         
     | 
| 
      
 69 
     | 
    
         
            +
                    now.strftime(LOG_TIME_FORMAT),
         
     | 
| 
       63 
70 
     | 
    
         
             
                    env[REQUEST_METHOD],
         
     | 
| 
       64 
71 
     | 
    
         
             
                    env[PATH_INFO],
         
     | 
| 
       65 
72 
     | 
    
         
             
                    env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
         
     | 
| 
       66 
     | 
    
         
            -
                    env[ 
     | 
| 
      
 73 
     | 
    
         
            +
                    env[HTTP_VERSION],
         
     | 
| 
       67 
74 
     | 
    
         
             
                    now - began_at ]
         
     | 
| 
       68 
75 
     | 
    
         | 
| 
       69 
76 
     | 
    
         
             
                  write(msg)
         
     | 
| 
         @@ -74,13 +81,13 @@ module Puma 
     | 
|
| 
       74 
81 
     | 
    
         
             
                  length = extract_content_length(header)
         
     | 
| 
       75 
82 
     | 
    
         | 
| 
       76 
83 
     | 
    
         
             
                  msg = FORMAT % [
         
     | 
| 
       77 
     | 
    
         
            -
                    env[ 
     | 
| 
       78 
     | 
    
         
            -
                    env[ 
     | 
| 
       79 
     | 
    
         
            -
                    now.strftime( 
     | 
| 
      
 84 
     | 
    
         
            +
                    env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
         
     | 
| 
      
 85 
     | 
    
         
            +
                    env[REMOTE_USER] || "-",
         
     | 
| 
      
 86 
     | 
    
         
            +
                    now.strftime(LOG_TIME_FORMAT),
         
     | 
| 
       80 
87 
     | 
    
         
             
                    env[REQUEST_METHOD],
         
     | 
| 
       81 
88 
     | 
    
         
             
                    env[PATH_INFO],
         
     | 
| 
       82 
89 
     | 
    
         
             
                    env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
         
     | 
| 
       83 
     | 
    
         
            -
                    env[ 
     | 
| 
      
 90 
     | 
    
         
            +
                    env[HTTP_VERSION],
         
     | 
| 
       84 
91 
     | 
    
         
             
                    status.to_s[0..3],
         
     | 
| 
       85 
92 
     | 
    
         
             
                    length,
         
     | 
| 
       86 
93 
     | 
    
         
             
                    now - began_at ]
         
     | 
    
        data/lib/puma/configuration.rb
    CHANGED
    
    | 
         @@ -1,20 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'rack/builder'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'plugin'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'const'
         
     | 
| 
      
 6 
     | 
    
         
            +
            # note that dsl is loaded at end of file, requires ConfigDefault constants
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            module Puma
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
              module ConfigDefault
         
     | 
| 
       10 
     | 
    
         
            -
                DefaultRackup = "config.ru"
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                DefaultTCPHost = "0.0.0.0"
         
     | 
| 
       13 
     | 
    
         
            -
                DefaultTCPPort = 9292
         
     | 
| 
       14 
     | 
    
         
            -
                DefaultWorkerTimeout = 60
         
     | 
| 
       15 
     | 
    
         
            -
                DefaultWorkerShutdownTimeout = 30
         
     | 
| 
       16 
     | 
    
         
            -
              end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
9 
     | 
    
         
             
              # A class used for storing "leveled" configuration options.
         
     | 
| 
       19 
10 
     | 
    
         
             
              #
         
     | 
| 
       20 
11 
     | 
    
         
             
              # In this class any "user" specified options take precedence over any
         
     | 
| 
         @@ -135,7 +126,50 @@ module Puma 
     | 
|
| 
       135 
126 
     | 
    
         
             
              # is done because an environment variable may have been modified while loading
         
     | 
| 
       136 
127 
     | 
    
         
             
              # configuration files.
         
     | 
| 
       137 
128 
     | 
    
         
             
              class Configuration
         
     | 
| 
       138 
     | 
    
         
            -
                 
     | 
| 
      
 129 
     | 
    
         
            +
                DEFAULTS = {
         
     | 
| 
      
 130 
     | 
    
         
            +
                  auto_trim_time: 30,
         
     | 
| 
      
 131 
     | 
    
         
            +
                  binds: ['tcp://0.0.0.0:9292'.freeze],
         
     | 
| 
      
 132 
     | 
    
         
            +
                  clean_thread_locals: false,
         
     | 
| 
      
 133 
     | 
    
         
            +
                  debug: false,
         
     | 
| 
      
 134 
     | 
    
         
            +
                  early_hints: nil,
         
     | 
| 
      
 135 
     | 
    
         
            +
                  environment: 'development'.freeze,
         
     | 
| 
      
 136 
     | 
    
         
            +
                  # Number of seconds to wait until we get the first data for the request
         
     | 
| 
      
 137 
     | 
    
         
            +
                  first_data_timeout: 30,
         
     | 
| 
      
 138 
     | 
    
         
            +
                  io_selector_backend: :auto,
         
     | 
| 
      
 139 
     | 
    
         
            +
                  log_requests: false,
         
     | 
| 
      
 140 
     | 
    
         
            +
                  logger: STDOUT,
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # How many requests to attempt inline before sending a client back to
         
     | 
| 
      
 142 
     | 
    
         
            +
                  # the reactor to be subject to normal ordering. The idea here is that
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # we amortize the cost of going back to the reactor for a well behaved
         
     | 
| 
      
 144 
     | 
    
         
            +
                  # but very "greedy" client across 10 requests. This prevents a not
         
     | 
| 
      
 145 
     | 
    
         
            +
                  # well behaved client from monopolizing the thread forever.
         
     | 
| 
      
 146 
     | 
    
         
            +
                  max_fast_inline: 10,
         
     | 
| 
      
 147 
     | 
    
         
            +
                  max_threads: Puma.mri? ? 5 : 16,
         
     | 
| 
      
 148 
     | 
    
         
            +
                  min_threads: 0,
         
     | 
| 
      
 149 
     | 
    
         
            +
                  mode: :http,
         
     | 
| 
      
 150 
     | 
    
         
            +
                  mutate_stdout_and_stderr_to_sync_on_write: true,
         
     | 
| 
      
 151 
     | 
    
         
            +
                  out_of_band: [],
         
     | 
| 
      
 152 
     | 
    
         
            +
                  # Number of seconds for another request within a persistent session.
         
     | 
| 
      
 153 
     | 
    
         
            +
                  persistent_timeout: 20,
         
     | 
| 
      
 154 
     | 
    
         
            +
                  queue_requests: true,
         
     | 
| 
      
 155 
     | 
    
         
            +
                  rackup: 'config.ru'.freeze,
         
     | 
| 
      
 156 
     | 
    
         
            +
                  raise_exception_on_sigterm: true,
         
     | 
| 
      
 157 
     | 
    
         
            +
                  reaping_time: 1,
         
     | 
| 
      
 158 
     | 
    
         
            +
                  remote_address: :socket,
         
     | 
| 
      
 159 
     | 
    
         
            +
                  silence_single_worker_warning: false,
         
     | 
| 
      
 160 
     | 
    
         
            +
                  silence_fork_callback_warning: false,
         
     | 
| 
      
 161 
     | 
    
         
            +
                  tag: File.basename(Dir.getwd),
         
     | 
| 
      
 162 
     | 
    
         
            +
                  tcp_host: '0.0.0.0'.freeze,
         
     | 
| 
      
 163 
     | 
    
         
            +
                  tcp_port: 9292,
         
     | 
| 
      
 164 
     | 
    
         
            +
                  wait_for_less_busy_worker: 0.005,
         
     | 
| 
      
 165 
     | 
    
         
            +
                  worker_boot_timeout: 60,
         
     | 
| 
      
 166 
     | 
    
         
            +
                  worker_check_interval: 5,
         
     | 
| 
      
 167 
     | 
    
         
            +
                  worker_culling_strategy: :youngest,
         
     | 
| 
      
 168 
     | 
    
         
            +
                  worker_shutdown_timeout: 30,
         
     | 
| 
      
 169 
     | 
    
         
            +
                  worker_timeout: 60,
         
     | 
| 
      
 170 
     | 
    
         
            +
                  workers: 0,
         
     | 
| 
      
 171 
     | 
    
         
            +
                  http_content_length_limit: nil
         
     | 
| 
      
 172 
     | 
    
         
            +
                }
         
     | 
| 
       139 
173 
     | 
    
         | 
| 
       140 
174 
     | 
    
         
             
                def initialize(user_options={}, default_options = {}, &block)
         
     | 
| 
       141 
175 
     | 
    
         
             
                  default_options = self.puma_default_options.merge(default_options)
         
     | 
| 
         @@ -180,34 +214,22 @@ module Puma 
     | 
|
| 
       180 
214 
     | 
    
         
             
                  self
         
     | 
| 
       181 
215 
     | 
    
         
             
                end
         
     | 
| 
       182 
216 
     | 
    
         | 
| 
       183 
     | 
    
         
            -
                 
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                   
     | 
| 
      
 217 
     | 
    
         
            +
                def puma_default_options
         
     | 
| 
      
 218 
     | 
    
         
            +
                  defaults = DEFAULTS.dup
         
     | 
| 
      
 219 
     | 
    
         
            +
                  puma_options_from_env.each { |k,v| defaults[k] = v if v }
         
     | 
| 
      
 220 
     | 
    
         
            +
                  defaults
         
     | 
| 
       186 
221 
     | 
    
         
             
                end
         
     | 
| 
       187 
222 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
                def  
     | 
| 
      
 223 
     | 
    
         
            +
                def puma_options_from_env
         
     | 
| 
      
 224 
     | 
    
         
            +
                  min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
         
     | 
| 
      
 225 
     | 
    
         
            +
                  max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
         
     | 
| 
      
 226 
     | 
    
         
            +
                  workers = ENV['WEB_CONCURRENCY']
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
       189 
228 
     | 
    
         
             
                  {
         
     | 
| 
       190 
     | 
    
         
            -
                    : 
     | 
| 
       191 
     | 
    
         
            -
                    : 
     | 
| 
       192 
     | 
    
         
            -
                    : 
     | 
| 
       193 
     | 
    
         
            -
                    : 
     | 
| 
       194 
     | 
    
         
            -
                    :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
         
     | 
| 
       195 
     | 
    
         
            -
                    :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
         
     | 
| 
       196 
     | 
    
         
            -
                    :mode => :http,
         
     | 
| 
       197 
     | 
    
         
            -
                    :worker_timeout => DefaultWorkerTimeout,
         
     | 
| 
       198 
     | 
    
         
            -
                    :worker_boot_timeout => DefaultWorkerTimeout,
         
     | 
| 
       199 
     | 
    
         
            -
                    :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
         
     | 
| 
       200 
     | 
    
         
            -
                    :remote_address => :socket,
         
     | 
| 
       201 
     | 
    
         
            -
                    :tag => method(:infer_tag),
         
     | 
| 
       202 
     | 
    
         
            -
                    :environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
         
     | 
| 
       203 
     | 
    
         
            -
                    :rackup => DefaultRackup,
         
     | 
| 
       204 
     | 
    
         
            -
                    :logger => STDOUT,
         
     | 
| 
       205 
     | 
    
         
            -
                    :persistent_timeout => Const::PERSISTENT_TIMEOUT,
         
     | 
| 
       206 
     | 
    
         
            -
                    :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
         
     | 
| 
       207 
     | 
    
         
            -
                    :raise_exception_on_sigterm => true,
         
     | 
| 
       208 
     | 
    
         
            -
                    :max_fast_inline => Const::MAX_FAST_INLINE,
         
     | 
| 
       209 
     | 
    
         
            -
                    :io_selector_backend => :auto,
         
     | 
| 
       210 
     | 
    
         
            -
                    :mutate_stdout_and_stderr_to_sync_on_write => true,
         
     | 
| 
      
 229 
     | 
    
         
            +
                    min_threads: min && Integer(min),
         
     | 
| 
      
 230 
     | 
    
         
            +
                    max_threads: max && Integer(max),
         
     | 
| 
      
 231 
     | 
    
         
            +
                    workers: workers && Integer(workers),
         
     | 
| 
      
 232 
     | 
    
         
            +
                    environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
         
     | 
| 
       211 
233 
     | 
    
         
             
                  }
         
     | 
| 
       212 
234 
     | 
    
         
             
                end
         
     | 
| 
       213 
235 
     | 
    
         | 
| 
         @@ -223,7 +245,7 @@ module Puma 
     | 
|
| 
       223 
245 
     | 
    
         
             
                  return [] if files == ['-']
         
     | 
| 
       224 
246 
     | 
    
         
             
                  return files if files.any?
         
     | 
| 
       225 
247 
     | 
    
         | 
| 
       226 
     | 
    
         
            -
                  first_default_file = %W(config/puma/#{ 
     | 
| 
      
 248 
     | 
    
         
            +
                  first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
         
     | 
| 
       227 
249 
     | 
    
         
             
                    File.exist?(f)
         
     | 
| 
       228 
250 
     | 
    
         
             
                  end
         
     | 
| 
       229 
251 
     | 
    
         | 
| 
         @@ -266,7 +288,7 @@ module Puma 
     | 
|
| 
       266 
288 
     | 
    
         
             
                  found = options[:app] || load_rackup
         
     | 
| 
       267 
289 
     | 
    
         | 
| 
       268 
290 
     | 
    
         
             
                  if @options[:log_requests]
         
     | 
| 
       269 
     | 
    
         
            -
                     
     | 
| 
      
 291 
     | 
    
         
            +
                    require_relative 'commonlogger'
         
     | 
| 
       270 
292 
     | 
    
         
             
                    logger = @options[:logger]
         
     | 
| 
       271 
293 
     | 
    
         
             
                    found = CommonLogger.new(found, logger)
         
     | 
| 
       272 
294 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -279,21 +301,25 @@ module Puma 
     | 
|
| 
       279 
301 
     | 
    
         
             
                  @options[:environment]
         
     | 
| 
       280 
302 
     | 
    
         
             
                end
         
     | 
| 
       281 
303 
     | 
    
         | 
| 
       282 
     | 
    
         
            -
                def environment_str
         
     | 
| 
       283 
     | 
    
         
            -
                  environment.respond_to?(:call) ? environment.call : environment
         
     | 
| 
       284 
     | 
    
         
            -
                end
         
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
304 
     | 
    
         
             
                def load_plugin(name)
         
     | 
| 
       287 
305 
     | 
    
         
             
                  @plugins.create name
         
     | 
| 
       288 
306 
     | 
    
         
             
                end
         
     | 
| 
       289 
307 
     | 
    
         | 
| 
       290 
     | 
    
         
            -
                 
     | 
| 
      
 308 
     | 
    
         
            +
                # @param key [:Symbol] hook to run
         
     | 
| 
      
 309 
     | 
    
         
            +
                # @param arg [Launcher, Int] `:on_restart` passes Launcher
         
     | 
| 
      
 310 
     | 
    
         
            +
                #
         
     | 
| 
      
 311 
     | 
    
         
            +
                def run_hooks(key, arg, log_writer, hook_data = nil)
         
     | 
| 
       291 
312 
     | 
    
         
             
                  @options.all_of(key).each do |b|
         
     | 
| 
       292 
313 
     | 
    
         
             
                    begin
         
     | 
| 
       293 
     | 
    
         
            -
                      b 
     | 
| 
      
 314 
     | 
    
         
            +
                      if Array === b
         
     | 
| 
      
 315 
     | 
    
         
            +
                        hook_data[b[1]] ||= Hash.new
         
     | 
| 
      
 316 
     | 
    
         
            +
                        b[0].call arg, hook_data[b[1]]
         
     | 
| 
      
 317 
     | 
    
         
            +
                      else
         
     | 
| 
      
 318 
     | 
    
         
            +
                        b.call arg
         
     | 
| 
      
 319 
     | 
    
         
            +
                      end
         
     | 
| 
       294 
320 
     | 
    
         
             
                    rescue => e
         
     | 
| 
       295 
     | 
    
         
            -
                       
     | 
| 
       296 
     | 
    
         
            -
                       
     | 
| 
      
 321 
     | 
    
         
            +
                      log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
         
     | 
| 
      
 322 
     | 
    
         
            +
                      log_writer.debug e.backtrace.join("\n")
         
     | 
| 
       297 
323 
     | 
    
         
             
                    end
         
     | 
| 
       298 
324 
     | 
    
         
             
                  end
         
     | 
| 
       299 
325 
     | 
    
         
             
                end
         
     | 
| 
         @@ -311,10 +337,6 @@ module Puma 
     | 
|
| 
       311 
337 
     | 
    
         | 
| 
       312 
338 
     | 
    
         
             
                private
         
     | 
| 
       313 
339 
     | 
    
         | 
| 
       314 
     | 
    
         
            -
                def infer_tag
         
     | 
| 
       315 
     | 
    
         
            -
                  File.basename(Dir.getwd)
         
     | 
| 
       316 
     | 
    
         
            -
                end
         
     | 
| 
       317 
     | 
    
         
            -
             
     | 
| 
       318 
340 
     | 
    
         
             
                # Load and use the normal Rack builder if we can, otherwise
         
     | 
| 
       319 
341 
     | 
    
         
             
                # fallback to our minimal version.
         
     | 
| 
       320 
342 
     | 
    
         
             
                def rack_builder
         
     | 
| 
         @@ -342,6 +364,8 @@ module Puma 
     | 
|
| 
       342 
364 
     | 
    
         
             
                  raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
         
     | 
| 
       343 
365 
     | 
    
         | 
| 
       344 
366 
     | 
    
         
             
                  rack_app, rack_options = rack_builder.parse_file(rackup)
         
     | 
| 
      
 367 
     | 
    
         
            +
                  rack_options = rack_options || {}
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
       345 
369 
     | 
    
         
             
                  @options.file_options.merge!(rack_options)
         
     | 
| 
       346 
370 
     | 
    
         | 
| 
       347 
371 
     | 
    
         
             
                  config_ru_binds = []
         
     | 
| 
         @@ -362,4 +386,4 @@ module Puma 
     | 
|
| 
       362 
386 
     | 
    
         
             
              end
         
     | 
| 
       363 
387 
     | 
    
         
             
            end
         
     | 
| 
       364 
388 
     | 
    
         | 
| 
       365 
     | 
    
         
            -
             
     | 
| 
      
 389 
     | 
    
         
            +
            require_relative 'dsl'
         
     |