puma 5.6.7 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +327 -16
  3. data/README.md +79 -29
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/kubernetes.md +12 -0
  8. data/docs/nginx.md +1 -1
  9. data/docs/restart.md +1 -0
  10. data/docs/systemd.md +3 -6
  11. data/docs/testing_benchmarks_local_files.md +150 -0
  12. data/docs/testing_test_rackup_ci_files.md +36 -0
  13. data/ext/puma_http11/extconf.rb +16 -9
  14. data/ext/puma_http11/http11_parser.c +1 -1
  15. data/ext/puma_http11/http11_parser.h +1 -1
  16. data/ext/puma_http11/http11_parser.java.rl +2 -2
  17. data/ext/puma_http11/http11_parser.rl +2 -2
  18. data/ext/puma_http11/http11_parser_common.rl +2 -2
  19. data/ext/puma_http11/mini_ssl.c +127 -19
  20. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  21. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  22. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
  23. data/ext/puma_http11/puma_http11.c +17 -9
  24. data/lib/puma/app/status.rb +4 -4
  25. data/lib/puma/binder.rb +50 -53
  26. data/lib/puma/cli.rb +16 -18
  27. data/lib/puma/client.rb +86 -19
  28. data/lib/puma/cluster/worker.rb +18 -11
  29. data/lib/puma/cluster/worker_handle.rb +4 -1
  30. data/lib/puma/cluster.rb +102 -40
  31. data/lib/puma/commonlogger.rb +21 -14
  32. data/lib/puma/configuration.rb +77 -59
  33. data/lib/puma/const.rb +129 -92
  34. data/lib/puma/control_cli.rb +15 -11
  35. data/lib/puma/detect.rb +7 -4
  36. data/lib/puma/dsl.rb +250 -56
  37. data/lib/puma/error_logger.rb +18 -9
  38. data/lib/puma/events.rb +6 -126
  39. data/lib/puma/io_buffer.rb +39 -4
  40. data/lib/puma/jruby_restart.rb +2 -1
  41. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  42. data/lib/puma/launcher.rb +102 -175
  43. data/lib/puma/log_writer.rb +147 -0
  44. data/lib/puma/minissl/context_builder.rb +26 -12
  45. data/lib/puma/minissl.rb +104 -11
  46. data/lib/puma/null_io.rb +16 -2
  47. data/lib/puma/plugin/systemd.rb +90 -0
  48. data/lib/puma/plugin/tmp_restart.rb +1 -1
  49. data/lib/puma/rack/builder.rb +6 -6
  50. data/lib/puma/rack/urlmap.rb +1 -1
  51. data/lib/puma/rack_default.rb +19 -4
  52. data/lib/puma/reactor.rb +19 -10
  53. data/lib/puma/request.rb +365 -170
  54. data/lib/puma/runner.rb +56 -20
  55. data/lib/puma/sd_notify.rb +149 -0
  56. data/lib/puma/server.rb +137 -89
  57. data/lib/puma/single.rb +13 -11
  58. data/lib/puma/state_file.rb +3 -6
  59. data/lib/puma/thread_pool.rb +57 -19
  60. data/lib/puma/util.rb +0 -11
  61. data/lib/puma.rb +9 -10
  62. data/lib/rack/handler/puma.rb +113 -86
  63. data/tools/Dockerfile +2 -2
  64. metadata +11 -7
  65. data/lib/puma/queue_close.rb +0 -26
  66. data/lib/puma/systemd.rb +0 -46
  67. data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/cluster.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/runner'
4
- require 'puma/util'
5
- require 'puma/plugin'
6
- require 'puma/cluster/worker_handle'
7
- require 'puma/cluster/worker'
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(cli, events)
21
- super cli, events
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 }
@@ -83,16 +85,14 @@ module Puma
83
85
  @workers << WorkerHandle.new(idx, pid, @phase, @options)
84
86
  end
85
87
 
86
- if @options[:fork_worker] &&
87
- @workers.all? {|x| x.phase == @phase}
88
-
88
+ if @options[:fork_worker] && all_workers_in_phase?
89
89
  @fork_writer << "0\n"
90
90
  end
91
91
  end
92
92
 
93
93
  # @version 5.0.0
94
94
  def spawn_worker(idx, master)
95
- @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
95
+ @config.run_hooks(:before_worker_fork, idx, @log_writer)
96
96
 
97
97
  pid = fork { worker(idx, master) }
98
98
  if !pid
@@ -101,7 +101,7 @@ module Puma
101
101
  exit! 1
102
102
  end
103
103
 
104
- @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
104
+ @config.run_hooks(:after_worker_fork, idx, @log_writer)
105
105
  pid
106
106
  end
107
107
 
@@ -146,10 +146,22 @@ module Puma
146
146
  idx
147
147
  end
148
148
 
149
+ def worker_at(idx)
150
+ @workers.find { |w| w.index == idx }
151
+ end
152
+
149
153
  def all_workers_booted?
150
154
  @workers.count { |w| !w.booted? } == 0
151
155
  end
152
156
 
157
+ def all_workers_in_phase?
158
+ @workers.all? { |w| w.phase == @phase }
159
+ end
160
+
161
+ def all_workers_idle_timed_out?
162
+ (@workers.map(&:pid) - idle_timed_out_worker_pids).empty?
163
+ end
164
+
153
165
  def check_workers
154
166
  return if @next_check >= Time.now
155
167
 
@@ -176,10 +188,10 @@ module Puma
176
188
  end
177
189
  end
178
190
 
179
- @next_check = [
180
- @workers.reject(&:term?).map(&:ping_timeout).min,
181
- @next_check
182
- ].compact.min
191
+ t = @workers.reject(&:term?)
192
+ t.map!(&:ping_timeout)
193
+
194
+ @next_check = [t.min, @next_check].compact.min
183
195
  end
184
196
 
185
197
  def worker(index, master)
@@ -209,8 +221,8 @@ module Puma
209
221
  stop
210
222
  end
211
223
 
212
- def phased_restart
213
- return false if @options[:preload_app]
224
+ def phased_restart(refork = false)
225
+ return false if @options[:preload_app] && !refork
214
226
 
215
227
  @phased_restart = true
216
228
  wakeup!
@@ -226,7 +238,7 @@ module Puma
226
238
  def stop_blocked
227
239
  @status = :stop if @status == :run
228
240
  wakeup!
229
- @control.stop(true) if @control
241
+ @control&.stop true
230
242
  Process.waitall
231
243
  end
232
244
 
@@ -248,24 +260,24 @@ module Puma
248
260
  old_worker_count = @workers.count { |w| w.phase != @phase }
249
261
  worker_status = @workers.map do |w|
250
262
  {
251
- started_at: w.started_at.utc.iso8601,
263
+ started_at: utc_iso8601(w.started_at),
252
264
  pid: w.pid,
253
265
  index: w.index,
254
266
  phase: w.phase,
255
267
  booted: w.booted?,
256
- last_checkin: w.last_checkin.utc.iso8601,
268
+ last_checkin: utc_iso8601(w.last_checkin),
257
269
  last_status: w.last_status,
258
270
  }
259
271
  end
260
272
 
261
273
  {
262
- started_at: @started_at.utc.iso8601,
274
+ started_at: utc_iso8601(@started_at),
263
275
  workers: @workers.size,
264
276
  phase: @phase,
265
277
  booted_workers: worker_status.count { |w| w[:booted] },
266
278
  old_workers: old_worker_count,
267
279
  worker_status: worker_status,
268
- }
280
+ }.merge(super)
269
281
  end
270
282
 
271
283
  def preload?
@@ -274,10 +286,10 @@ module Puma
274
286
 
275
287
  # @version 5.0.0
276
288
  def fork_worker!
277
- if (worker = @workers.find { |w| w.index == 0 })
289
+ if (worker = worker_at 0)
278
290
  worker.phase += 1
279
291
  end
280
- phased_restart
292
+ phased_restart(true)
281
293
  end
282
294
 
283
295
  # We do this in a separate method to keep the lambda scope
@@ -290,7 +302,7 @@ module Puma
290
302
 
291
303
  # Auto-fork after the specified number of requests.
292
304
  if (fork_requests = @options[:fork_worker].to_i) > 0
293
- @launcher.events.register(:ping!) do |w|
305
+ @events.register(:ping!) do |w|
294
306
  fork_worker! if w.index == 0 &&
295
307
  w.phase == 0 &&
296
308
  w.last_status[:requests_count] >= fork_requests
@@ -336,6 +348,8 @@ module Puma
336
348
  def run
337
349
  @status = :run
338
350
 
351
+ @idle_workers = {}
352
+
339
353
  output_header "cluster"
340
354
 
341
355
  # This is aligned with the output from Runner, see Runner#output_header
@@ -372,12 +386,12 @@ module Puma
372
386
  else
373
387
  log "* Restarts: (\u2714) hot (\u2714) phased"
374
388
 
375
- unless @launcher.config.app_configured?
389
+ unless @config.app_configured?
376
390
  error "No application configured, nothing to run"
377
391
  exit 1
378
392
  end
379
393
 
380
- @launcher.binder.parse @options[:binds], self
394
+ @launcher.binder.parse @options[:binds]
381
395
  end
382
396
 
383
397
  read, @wakeup = Puma::Util.pipe
@@ -409,8 +423,9 @@ module Puma
409
423
 
410
424
  @master_read, @worker_write = read, @wakeup
411
425
 
412
- @launcher.config.run_hooks :before_fork, nil, @launcher.events
413
- Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
426
+ @options[:worker_write] = @worker_write
427
+
428
+ @config.run_hooks(:before_fork, nil, @log_writer)
414
429
 
415
430
  spawn_workers
416
431
 
@@ -425,6 +440,11 @@ module Puma
425
440
 
426
441
  while @status == :run
427
442
  begin
443
+ if all_workers_idle_timed_out?
444
+ log "- All workers reached idle timeout"
445
+ break
446
+ end
447
+
428
448
  if @phased_restart
429
449
  start_phased_restart
430
450
  @phased_restart = false
@@ -445,7 +465,7 @@ module Puma
445
465
 
446
466
  if req == "b" || req == "f"
447
467
  pid, idx = result.split(':').map(&:to_i)
448
- w = @workers.find {|x| x.index == idx}
468
+ w = worker_at idx
449
469
  w.pid = pid if w.pid.nil?
450
470
  end
451
471
 
@@ -462,22 +482,37 @@ module Puma
462
482
  when "t"
463
483
  w.term unless w.term?
464
484
  when "p"
465
- w.ping!(result.sub(/^\d+/,'').chomp)
466
- @launcher.events.fire(:ping!, w)
485
+ status = result.sub(/^\d+/,'').chomp
486
+ w.ping!(status)
487
+ @events.fire(:ping!, w)
488
+
489
+ if in_phased_restart && workers_not_booted.positive? && w0 = worker_at(0)
490
+ w0.ping!(status)
491
+ @events.fire(:ping!, w0)
492
+ end
493
+
467
494
  if !booted && @workers.none? {|worker| worker.last_status.empty?}
468
- @launcher.events.fire_on_booted!
495
+ @events.fire_on_booted!
496
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
469
497
  booted = true
470
498
  end
499
+ when "i"
500
+ if @idle_workers[pid]
501
+ @idle_workers.delete pid
502
+ else
503
+ @idle_workers[pid] = true
504
+ end
471
505
  end
472
506
  else
473
507
  log "! Out-of-sync worker list, no #{pid} worker"
474
508
  end
475
509
  end
510
+
476
511
  if in_phased_restart && workers_not_booted.zero?
477
512
  @events.fire_on_booted!
513
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
478
514
  in_phased_restart = false
479
515
  end
480
-
481
516
  rescue Interrupt
482
517
  @status = :stop
483
518
  end
@@ -506,10 +541,28 @@ module Puma
506
541
  # loops thru @workers, removing workers that exited, and calling
507
542
  # `#term` if needed
508
543
  def wait_workers
544
+ # Reap all children, known workers or otherwise.
545
+ # If puma has PID 1, as it's common in containerized environments,
546
+ # then it's responsible for reaping orphaned processes, so we must reap
547
+ # all our dead children, regardless of whether they are workers we spawned
548
+ # or some reattached processes.
549
+ reaped_children = {}
550
+ loop do
551
+ begin
552
+ pid, status = Process.wait2(-1, Process::WNOHANG)
553
+ break unless pid
554
+ reaped_children[pid] = status
555
+ rescue Errno::ECHILD
556
+ break
557
+ end
558
+ end
559
+
509
560
  @workers.reject! do |w|
510
561
  next false if w.pid.nil?
511
562
  begin
512
- if Process.wait(w.pid, Process::WNOHANG)
563
+ # When `fork_worker` is enabled, some worker may not be direct children, but grand children.
564
+ # Because of this they won't be reaped by `Process.wait2(-1)`, so we need to check them individually)
565
+ if reaped_children.delete(w.pid) || (@options[:fork_worker] && Process.wait(w.pid, Process::WNOHANG))
513
566
  true
514
567
  else
515
568
  w.term if w.term?
@@ -526,6 +579,11 @@ module Puma
526
579
  end
527
580
  end
528
581
  end
582
+
583
+ # Log unknown children
584
+ reaped_children.each do |pid, status|
585
+ log "! reaped unknown child process pid=#{pid} status=#{status}"
586
+ end
529
587
  end
530
588
 
531
589
  # @version 5.0.0
@@ -533,14 +591,18 @@ module Puma
533
591
  @workers.each do |w|
534
592
  if !w.term? && w.ping_timeout <= Time.now
535
593
  details = if w.booted?
536
- "(worker failed to check in within #{@options[:worker_timeout]} seconds)"
594
+ "(Worker #{w.index} failed to check in within #{@options[:worker_timeout]} seconds)"
537
595
  else
538
- "(worker failed to boot within #{@options[:worker_boot_timeout]} seconds)"
596
+ "(Worker #{w.index} failed to boot within #{@options[:worker_boot_timeout]} seconds)"
539
597
  end
540
598
  log "! Terminating timed out worker #{details}: #{w.pid}"
541
599
  w.kill
542
600
  end
543
601
  end
544
602
  end
603
+
604
+ def idle_timed_out_worker_pids
605
+ @idle_workers.keys
606
+ end
545
607
  end
546
608
  end
@@ -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/1.3/logs.html#common]
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/1.3/logs.html#common
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
- CONTENT_LENGTH = 'Content-Length'.freeze
29
- PATH_INFO = 'PATH_INFO'.freeze
30
- QUERY_STRING = 'QUERY_STRING'.freeze
31
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
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['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
61
- env["REMOTE_USER"] || "-",
62
- now.strftime("%d/%b/%Y %H:%M:%S"),
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["HTTP_VERSION"],
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['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
78
- env["REMOTE_USER"] || "-",
79
- now.strftime("%d/%b/%Y:%H:%M:%S %z"),
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["HTTP_VERSION"],
90
+ env[HTTP_VERSION],
84
91
  status.to_s[0..3],
85
92
  length,
86
93
  now - began_at ]
@@ -1,21 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/rack/builder'
4
- require 'puma/plugin'
5
- require 'puma/const'
3
+ require_relative 'rack/builder'
4
+ require_relative 'plugin'
5
+ require_relative 'const'
6
+ require_relative 'dsl'
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
- DefaultWorkerCheckInterval = 5
15
- DefaultWorkerTimeout = 60
16
- DefaultWorkerShutdownTimeout = 30
17
- end
18
-
19
9
  # A class used for storing "leveled" configuration options.
20
10
  #
21
11
  # In this class any "user" specified options take precedence over any
@@ -136,7 +126,52 @@ module Puma
136
126
  # is done because an environment variable may have been modified while loading
137
127
  # configuration files.
138
128
  class Configuration
139
- include ConfigDefault
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
+ # Number of seconds to wait until the next request before shutting down.
139
+ idle_timeout: nil,
140
+ io_selector_backend: :auto,
141
+ log_requests: false,
142
+ logger: STDOUT,
143
+ # How many requests to attempt inline before sending a client back to
144
+ # the reactor to be subject to normal ordering. The idea here is that
145
+ # we amortize the cost of going back to the reactor for a well behaved
146
+ # but very "greedy" client across 10 requests. This prevents a not
147
+ # well behaved client from monopolizing the thread forever.
148
+ max_fast_inline: 10,
149
+ max_threads: Puma.mri? ? 5 : 16,
150
+ min_threads: 0,
151
+ mode: :http,
152
+ mutate_stdout_and_stderr_to_sync_on_write: true,
153
+ out_of_band: [],
154
+ # Number of seconds for another request within a persistent session.
155
+ persistent_timeout: 20,
156
+ queue_requests: true,
157
+ rackup: 'config.ru'.freeze,
158
+ raise_exception_on_sigterm: true,
159
+ reaping_time: 1,
160
+ remote_address: :socket,
161
+ silence_single_worker_warning: false,
162
+ silence_fork_callback_warning: false,
163
+ tag: File.basename(Dir.getwd),
164
+ tcp_host: '0.0.0.0'.freeze,
165
+ tcp_port: 9292,
166
+ wait_for_less_busy_worker: 0.005,
167
+ worker_boot_timeout: 60,
168
+ worker_check_interval: 5,
169
+ worker_culling_strategy: :youngest,
170
+ worker_shutdown_timeout: 30,
171
+ worker_timeout: 60,
172
+ workers: 0,
173
+ http_content_length_limit: nil
174
+ }
140
175
 
141
176
  def initialize(user_options={}, default_options = {}, &block)
142
177
  default_options = self.puma_default_options.merge(default_options)
@@ -181,37 +216,22 @@ module Puma
181
216
  self
182
217
  end
183
218
 
184
- # @version 5.0.0
185
- def default_max_threads
186
- Puma.mri? ? 5 : 16
219
+ def puma_default_options
220
+ defaults = DEFAULTS.dup
221
+ puma_options_from_env.each { |k,v| defaults[k] = v if v }
222
+ defaults
187
223
  end
188
224
 
189
- def puma_default_options
225
+ def puma_options_from_env
226
+ min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
227
+ max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
228
+ workers = ENV['WEB_CONCURRENCY']
229
+
190
230
  {
191
- :min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
192
- :max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
193
- :log_requests => false,
194
- :debug => false,
195
- :binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
196
- :workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
197
- :silence_single_worker_warning => false,
198
- :mode => :http,
199
- :worker_check_interval => DefaultWorkerCheckInterval,
200
- :worker_timeout => DefaultWorkerTimeout,
201
- :worker_boot_timeout => DefaultWorkerTimeout,
202
- :worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
203
- :worker_culling_strategy => :youngest,
204
- :remote_address => :socket,
205
- :tag => method(:infer_tag),
206
- :environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
207
- :rackup => DefaultRackup,
208
- :logger => STDOUT,
209
- :persistent_timeout => Const::PERSISTENT_TIMEOUT,
210
- :first_data_timeout => Const::FIRST_DATA_TIMEOUT,
211
- :raise_exception_on_sigterm => true,
212
- :max_fast_inline => Const::MAX_FAST_INLINE,
213
- :io_selector_backend => :auto,
214
- :mutate_stdout_and_stderr_to_sync_on_write => true,
231
+ min_threads: min && Integer(min),
232
+ max_threads: max && Integer(max),
233
+ workers: workers && Integer(workers),
234
+ environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
215
235
  }
216
236
  end
217
237
 
@@ -227,7 +247,7 @@ module Puma
227
247
  return [] if files == ['-']
228
248
  return files if files.any?
229
249
 
230
- first_default_file = %W(config/puma/#{environment_str}.rb config/puma.rb).find do |f|
250
+ first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
231
251
  File.exist?(f)
232
252
  end
233
253
 
@@ -270,7 +290,7 @@ module Puma
270
290
  found = options[:app] || load_rackup
271
291
 
272
292
  if @options[:log_requests]
273
- require 'puma/commonlogger'
293
+ require_relative 'commonlogger'
274
294
  logger = @options[:logger]
275
295
  found = CommonLogger.new(found, logger)
276
296
  end
@@ -283,21 +303,25 @@ module Puma
283
303
  @options[:environment]
284
304
  end
285
305
 
286
- def environment_str
287
- environment.respond_to?(:call) ? environment.call : environment
288
- end
289
-
290
306
  def load_plugin(name)
291
307
  @plugins.create name
292
308
  end
293
309
 
294
- def run_hooks(key, arg, events)
310
+ # @param key [:Symbol] hook to run
311
+ # @param arg [Launcher, Int] `:on_restart` passes Launcher
312
+ #
313
+ def run_hooks(key, arg, log_writer, hook_data = nil)
295
314
  @options.all_of(key).each do |b|
296
315
  begin
297
- b.call arg
316
+ if Array === b
317
+ hook_data[b[1]] ||= Hash.new
318
+ b[0].call arg, hook_data[b[1]]
319
+ else
320
+ b.call arg
321
+ end
298
322
  rescue => e
299
- events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
300
- events.debug e.backtrace.join("\n")
323
+ log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
324
+ log_writer.debug e.backtrace.join("\n")
301
325
  end
302
326
  end
303
327
  end
@@ -315,10 +339,6 @@ module Puma
315
339
 
316
340
  private
317
341
 
318
- def infer_tag
319
- File.basename(Dir.getwd)
320
- end
321
-
322
342
  # Load and use the normal Rack builder if we can, otherwise
323
343
  # fallback to our minimal version.
324
344
  def rack_builder
@@ -367,5 +387,3 @@ module Puma
367
387
  end
368
388
  end
369
389
  end
370
-
371
- require 'puma/dsl'