tiny-fast-gem 0.0.1

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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/puma-8.0.2/History.md +3334 -0
  3. data/puma-8.0.2/LICENSE +29 -0
  4. data/puma-8.0.2/README.md +484 -0
  5. data/puma-8.0.2/bin/puma +10 -0
  6. data/puma-8.0.2/bin/puma-wild +25 -0
  7. data/puma-8.0.2/bin/pumactl +12 -0
  8. data/puma-8.0.2/docs/5.0-Upgrade.md +98 -0
  9. data/puma-8.0.2/docs/6.0-Upgrade.md +56 -0
  10. data/puma-8.0.2/docs/7.0-Upgrade.md +52 -0
  11. data/puma-8.0.2/docs/8.0-Upgrade.md +100 -0
  12. data/puma-8.0.2/docs/architecture.md +74 -0
  13. data/puma-8.0.2/docs/compile_options.md +55 -0
  14. data/puma-8.0.2/docs/deployment.md +137 -0
  15. data/puma-8.0.2/docs/fork_worker.md +41 -0
  16. data/puma-8.0.2/docs/grpc.md +62 -0
  17. data/puma-8.0.2/docs/images/favicon.svg +1 -0
  18. data/puma-8.0.2/docs/images/puma-connection-flow-no-reactor.png +0 -0
  19. data/puma-8.0.2/docs/images/puma-connection-flow.png +0 -0
  20. data/puma-8.0.2/docs/images/puma-general-arch.png +0 -0
  21. data/puma-8.0.2/docs/images/running-puma.svg +1 -0
  22. data/puma-8.0.2/docs/images/standard-logo.svg +1 -0
  23. data/puma-8.0.2/docs/java_options.md +54 -0
  24. data/puma-8.0.2/docs/jungle/README.md +9 -0
  25. data/puma-8.0.2/docs/jungle/rc.d/README.md +74 -0
  26. data/puma-8.0.2/docs/jungle/rc.d/puma +61 -0
  27. data/puma-8.0.2/docs/jungle/rc.d/puma.conf +10 -0
  28. data/puma-8.0.2/docs/kubernetes.md +73 -0
  29. data/puma-8.0.2/docs/nginx.md +80 -0
  30. data/puma-8.0.2/docs/plugins.md +42 -0
  31. data/puma-8.0.2/docs/rails_dev_mode.md +28 -0
  32. data/puma-8.0.2/docs/restart.md +65 -0
  33. data/puma-8.0.2/docs/signals.md +98 -0
  34. data/puma-8.0.2/docs/stats.md +148 -0
  35. data/puma-8.0.2/docs/systemd.md +253 -0
  36. data/puma-8.0.2/docs/testing_benchmarks_local_files.md +150 -0
  37. data/puma-8.0.2/docs/testing_test_rackup_ci_files.md +36 -0
  38. data/puma-8.0.2/ext/puma_http11/PumaHttp11Service.java +17 -0
  39. data/puma-8.0.2/ext/puma_http11/extconf.rb +65 -0
  40. data/puma-8.0.2/ext/puma_http11/http11_parser.c +1057 -0
  41. data/puma-8.0.2/ext/puma_http11/http11_parser.h +65 -0
  42. data/puma-8.0.2/ext/puma_http11/http11_parser.java.rl +131 -0
  43. data/puma-8.0.2/ext/puma_http11/http11_parser.rl +149 -0
  44. data/puma-8.0.2/ext/puma_http11/http11_parser_common.rl +54 -0
  45. data/puma-8.0.2/ext/puma_http11/mini_ssl.c +852 -0
  46. data/puma-8.0.2/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  47. data/puma-8.0.2/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
  48. data/puma-8.0.2/ext/puma_http11/org/jruby/puma/Http11.java +321 -0
  49. data/puma-8.0.2/ext/puma_http11/org/jruby/puma/Http11Parser.java +441 -0
  50. data/puma-8.0.2/ext/puma_http11/org/jruby/puma/MiniSSL.java +509 -0
  51. data/puma-8.0.2/ext/puma_http11/puma_http11.c +499 -0
  52. data/puma-8.0.2/lib/puma/app/status.rb +104 -0
  53. data/puma-8.0.2/lib/puma/binder.rb +511 -0
  54. data/puma-8.0.2/lib/puma/cli.rb +245 -0
  55. data/puma-8.0.2/lib/puma/client.rb +756 -0
  56. data/puma-8.0.2/lib/puma/client_env.rb +171 -0
  57. data/puma-8.0.2/lib/puma/cluster/worker.rb +183 -0
  58. data/puma-8.0.2/lib/puma/cluster/worker_handle.rb +127 -0
  59. data/puma-8.0.2/lib/puma/cluster.rb +634 -0
  60. data/puma-8.0.2/lib/puma/cluster_accept_loop_delay.rb +91 -0
  61. data/puma-8.0.2/lib/puma/commonlogger.rb +115 -0
  62. data/puma-8.0.2/lib/puma/configuration.rb +522 -0
  63. data/puma-8.0.2/lib/puma/const.rb +308 -0
  64. data/puma-8.0.2/lib/puma/control_cli.rb +320 -0
  65. data/puma-8.0.2/lib/puma/detect.rb +58 -0
  66. data/puma-8.0.2/lib/puma/dsl.rb +1562 -0
  67. data/puma-8.0.2/lib/puma/error_logger.rb +115 -0
  68. data/puma-8.0.2/lib/puma/events.rb +72 -0
  69. data/puma-8.0.2/lib/puma/io_buffer.rb +50 -0
  70. data/puma-8.0.2/lib/puma/jruby_restart.rb +11 -0
  71. data/puma-8.0.2/lib/puma/json_serialization.rb +96 -0
  72. data/puma-8.0.2/lib/puma/launcher/bundle_pruner.rb +102 -0
  73. data/puma-8.0.2/lib/puma/launcher.rb +501 -0
  74. data/puma-8.0.2/lib/puma/log_writer.rb +153 -0
  75. data/puma-8.0.2/lib/puma/minissl/context_builder.rb +96 -0
  76. data/puma-8.0.2/lib/puma/minissl.rb +458 -0
  77. data/puma-8.0.2/lib/puma/null_io.rb +101 -0
  78. data/puma-8.0.2/lib/puma/plugin/systemd.rb +90 -0
  79. data/puma-8.0.2/lib/puma/plugin/tmp_restart.rb +36 -0
  80. data/puma-8.0.2/lib/puma/plugin.rb +111 -0
  81. data/puma-8.0.2/lib/puma/rack/builder.rb +297 -0
  82. data/puma-8.0.2/lib/puma/rack/urlmap.rb +93 -0
  83. data/puma-8.0.2/lib/puma/rack_default.rb +24 -0
  84. data/puma-8.0.2/lib/puma/reactor.rb +131 -0
  85. data/puma-8.0.2/lib/puma/response.rb +532 -0
  86. data/puma-8.0.2/lib/puma/runner.rb +211 -0
  87. data/puma-8.0.2/lib/puma/sd_notify.rb +146 -0
  88. data/puma-8.0.2/lib/puma/server.rb +773 -0
  89. data/puma-8.0.2/lib/puma/server_plugin_control.rb +32 -0
  90. data/puma-8.0.2/lib/puma/single.rb +72 -0
  91. data/puma-8.0.2/lib/puma/state_file.rb +69 -0
  92. data/puma-8.0.2/lib/puma/thread_pool.rb +517 -0
  93. data/puma-8.0.2/lib/puma/util.rb +134 -0
  94. data/puma-8.0.2/lib/puma.rb +88 -0
  95. data/puma-8.0.2/lib/rack/handler/puma.rb +144 -0
  96. data/puma-8.0.2/tools/Dockerfile +26 -0
  97. data/puma-8.0.2/tools/trickletest.rb +44 -0
  98. data/tiny-fast-gem.gemspec +12 -0
  99. metadata +138 -0
@@ -0,0 +1,522 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+ require 'uri'
5
+
6
+ require_relative 'plugin'
7
+ require_relative 'const'
8
+ require_relative 'dsl'
9
+ require_relative 'events'
10
+
11
+ module Puma
12
+ # A class used for storing "leveled" configuration options.
13
+ #
14
+ # In this class any "user" specified options take precedence over any
15
+ # "file" specified options, take precedence over any "default" options.
16
+ #
17
+ # User input is preferred over "defaults":
18
+ # user_options = { foo: "bar" }
19
+ # default_options = { foo: "zoo" }
20
+ # options = UserFileDefaultOptions.new(user_options, default_options)
21
+ # puts options[:foo]
22
+ # # => "bar"
23
+ #
24
+ # All values can be accessed via `all_of`
25
+ #
26
+ # puts options.all_of(:foo)
27
+ # # => ["bar", "zoo"]
28
+ #
29
+ # A "file" option can be set. This config will be preferred over "default" options
30
+ # but will defer to any available "user" specified options.
31
+ #
32
+ # user_options = { foo: "bar" }
33
+ # default_options = { rackup: "zoo.rb" }
34
+ # options = UserFileDefaultOptions.new(user_options, default_options)
35
+ # options.file_options[:rackup] = "sup.rb"
36
+ # puts options[:rackup]
37
+ # # => "sup.rb"
38
+ #
39
+ # The "default" options can be set via procs. These are resolved during runtime
40
+ # via calls to `finalize_values`
41
+ class UserFileDefaultOptions
42
+ def initialize(user_options, default_options)
43
+ @user_options = user_options
44
+ @file_options = {}
45
+ @default_options = default_options
46
+ end
47
+
48
+ attr_reader :user_options, :file_options, :default_options
49
+
50
+ def [](key)
51
+ fetch(key)
52
+ end
53
+
54
+ def []=(key, value)
55
+ user_options[key] = value
56
+ end
57
+
58
+ def fetch(key, default_value = nil)
59
+ return user_options[key] if user_options.key?(key)
60
+ return file_options[key] if file_options.key?(key)
61
+ return default_options[key] if default_options.key?(key)
62
+
63
+ default_value
64
+ end
65
+
66
+ def all_of(key)
67
+ user = user_options[key]
68
+ file = file_options[key]
69
+ default = default_options[key]
70
+
71
+ user = [user] unless user.is_a?(Array)
72
+ file = [file] unless file.is_a?(Array)
73
+ default = [default] unless default.is_a?(Array)
74
+
75
+ user.compact!
76
+ file.compact!
77
+ default.compact!
78
+
79
+ user + file + default
80
+ end
81
+
82
+ def finalize_values
83
+ @default_options.each do |k,v|
84
+ if v.respond_to? :call
85
+ @default_options[k] = v.call
86
+ end
87
+ end
88
+ end
89
+
90
+ def final_options
91
+ default_options
92
+ .merge(file_options)
93
+ .merge(user_options)
94
+ end
95
+ end
96
+
97
+ # The main configuration class of Puma.
98
+ #
99
+ # It can be initialized with a set of "user" options and "default" options.
100
+ # Defaults will be merged with `Configuration.puma_default_options`.
101
+ #
102
+ # This class works together with 2 main other classes the `UserFileDefaultOptions`
103
+ # which stores configuration options in order so the precedence is that user
104
+ # set configuration wins over "file" based configuration wins over "default"
105
+ # configuration. These configurations are set via the `DSL` class. This
106
+ # class powers the Puma config file syntax and does double duty as a configuration
107
+ # DSL used by the `Puma::CLI` and Puma rack handler.
108
+ #
109
+ # It also handles loading plugins.
110
+ #
111
+ # [Note:]
112
+ # `:port` and `:host` are not valid keys. By the time they make it to the
113
+ # configuration options they are expected to be incorporated into a `:binds` key.
114
+ # Under the hood the DSL maps `port` and `host` calls to `:binds`
115
+ #
116
+ # config = Configuration.new({}) do |user_config, file_config, default_config|
117
+ # user_config.port 3003
118
+ # end
119
+ # config.clamp
120
+ # puts config.options[:port]
121
+ # # => 3003
122
+ #
123
+ # It is expected that `load` is called on the configuration instance after setting
124
+ # config. This method expands any values in `config_file` and puts them into the
125
+ # correct configuration option hash.
126
+ #
127
+ # Once all configuration is complete it is expected that `clamp` will be called
128
+ # on the instance. This will expand any procs stored under "default" values. This
129
+ # is done because an environment variable may have been modified while loading
130
+ # configuration files.
131
+ class Configuration
132
+ class NotLoadedError < StandardError; end
133
+ class NotClampedError < StandardError; end
134
+
135
+ DEFAULTS = {
136
+ auto_trim_time: 30,
137
+ binds: ['tcp://[::]:9292'.freeze],
138
+ debug: false,
139
+ early_hints: nil,
140
+ enable_keep_alives: true,
141
+ environment: 'development'.freeze,
142
+ fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
143
+ # Number of seconds to wait until we get the first data for the request.
144
+ first_data_timeout: 30,
145
+ force_shutdown_after: -1,
146
+ http_content_length_limit: nil,
147
+ # Number of seconds to wait until the next request before shutting down.
148
+ idle_timeout: nil,
149
+ io_selector_backend: :auto,
150
+ log_requests: false,
151
+ logger: STDOUT,
152
+ # Limits how many requests a keep alive connection can make.
153
+ # The connection will be closed after it reaches `max_keep_alive`
154
+ # requests.
155
+ max_io_threads: 0,
156
+ max_keep_alive: 999,
157
+ max_threads: Puma.mri? ? 5 : 16,
158
+ min_threads: 0,
159
+ mode: :http,
160
+ mutate_stdout_and_stderr_to_sync_on_write: true,
161
+ out_of_band: [],
162
+ # Number of seconds for another request within a persistent session.
163
+ persistent_timeout: 65, # PUMA_PERSISTENT_TIMEOUT
164
+ prune_bundler: false,
165
+ queue_requests: true,
166
+ rackup: 'config.ru'.freeze,
167
+ raise_exception_on_sigterm: true,
168
+ reaping_time: 1,
169
+ remote_address: :socket,
170
+ silence_fork_callback_warning: false,
171
+ silence_single_worker_warning: false,
172
+ tag: File.basename(Dir.getwd),
173
+ tcp_host: '::'.freeze,
174
+ tcp_port: 9292,
175
+ wait_for_less_busy_worker: 0.005,
176
+ worker_boot_timeout: 60,
177
+ worker_check_interval: 5,
178
+ worker_culling_strategy: :youngest,
179
+ worker_shutdown_timeout: 30,
180
+ worker_timeout: 60,
181
+ workers: 0,
182
+ }
183
+
184
+ def initialize(user_options={}, default_options = {}, env = ENV, &block)
185
+ default_options = self.puma_default_options(env).merge(events: Events.new).merge(default_options)
186
+
187
+ @_options = UserFileDefaultOptions.new(user_options, default_options)
188
+ @plugins = PluginLoader.new
189
+ @events = @_options[:events] || Events.new
190
+ @hooks = {}
191
+ @user_dsl = DSL.new(@_options.user_options, self)
192
+ @file_dsl = DSL.new(@_options.file_options, self)
193
+ @default_dsl = DSL.new(@_options.default_options, self)
194
+
195
+ @puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
196
+
197
+ if block
198
+ configure(&block)
199
+ end
200
+
201
+ @loaded = false
202
+ @clamped = false
203
+ end
204
+
205
+ attr_reader :plugins, :events, :hooks, :_options
206
+
207
+ def options
208
+ raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
209
+
210
+ @_options
211
+ end
212
+
213
+ def configure
214
+ yield @user_dsl, @file_dsl, @default_dsl
215
+ ensure
216
+ @user_dsl._offer_plugins
217
+ @file_dsl._offer_plugins
218
+ @default_dsl._offer_plugins
219
+ end
220
+
221
+ def initialize_copy(other)
222
+ @conf = nil
223
+ @cli_options = nil
224
+ @_options = @_options.dup
225
+ end
226
+
227
+ def flatten
228
+ dup.flatten!
229
+ end
230
+
231
+ def flatten!
232
+ @_options = @_options.flatten
233
+ self
234
+ end
235
+
236
+ def puma_default_options(env = ENV)
237
+ defaults = DEFAULTS.dup
238
+ defaults[:tcp_host] = self.class.default_tcp_host
239
+ defaults[:binds] = [self.class.default_tcp_bind]
240
+ puma_options_from_env(env).each { |k,v| defaults[k] = v if v }
241
+ defaults
242
+ end
243
+
244
+ def puma_options_from_env(env = ENV)
245
+ min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
246
+ max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
247
+ persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
248
+ workers_env = env['WEB_CONCURRENCY']
249
+ workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
250
+
251
+ {
252
+ min_threads: min && min != "" && Integer(min),
253
+ max_threads: max && max != "" && Integer(max),
254
+ persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
255
+ workers: workers,
256
+ environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
257
+ }
258
+ end
259
+
260
+ def load
261
+ @loaded = true
262
+ config_files.each { |config_file| @file_dsl._load_from(config_file) }
263
+ @_options
264
+ end
265
+
266
+ def config_files
267
+ raise NotLoadedError, "ensure load is called before accessing config_files" unless @loaded
268
+
269
+ files = @_options.all_of(:config_files)
270
+
271
+ return [] if files == ['-']
272
+ return files if files.any?
273
+
274
+ first_default_file = %W(config/puma/#{@_options[:environment]}.rb config/puma.rb).find do |f|
275
+ File.exist?(f)
276
+ end
277
+
278
+ [first_default_file]
279
+ end
280
+
281
+ # Call once all configuration (included from rackup files)
282
+ # is loaded to finalize defaults and lock in the configuration.
283
+ #
284
+ # This also calls load if it hasn't been called yet.
285
+ def clamp
286
+ load unless @loaded
287
+ run_mode_hooks
288
+ set_conditional_default_options
289
+ @_options.finalize_values
290
+ rewrite_unavailable_ipv6_binds!
291
+ @clamped = true
292
+ warn_hooks
293
+ options
294
+ end
295
+
296
+ # Injects the Configuration object into the env
297
+ class ConfigMiddleware
298
+ def initialize(config, app)
299
+ @config = config
300
+ @app = app
301
+ end
302
+
303
+ def call(env)
304
+ env[Const::PUMA_CONFIG] = @config
305
+ @app.call(env)
306
+ end
307
+ end
308
+
309
+ # Indicate if there is a properly configured app
310
+ #
311
+ def app_configured?
312
+ options[:app] || File.exist?(rackup)
313
+ end
314
+
315
+ def rackup
316
+ options[:rackup]
317
+ end
318
+
319
+ # Load the specified rackup file, pull options from
320
+ # the rackup file, and set @app.
321
+ #
322
+ def app
323
+ found = options[:app] || load_rackup
324
+
325
+ if options[:log_requests]
326
+ require_relative 'commonlogger'
327
+ logger = options[:custom_logger] ? options[:custom_logger] : options[:logger]
328
+ found = CommonLogger.new(found, logger)
329
+ end
330
+
331
+ ConfigMiddleware.new(self, found)
332
+ end
333
+
334
+ # Return which environment we're running in
335
+ def environment
336
+ options[:environment]
337
+ end
338
+
339
+ def load_plugin(name)
340
+ @plugins.create name
341
+ end
342
+
343
+ # @param key [:Symbol] hook to run
344
+ # @param arg [Launcher, Int] `:before_restart` passes Launcher
345
+ #
346
+ def run_hooks(key, arg, log_writer, hook_data = nil)
347
+ log_writer.debug { "Running #{key} hooks" }
348
+
349
+ options.all_of(key).each do |hook_options|
350
+ begin
351
+ block = hook_options[:block]
352
+ if id = hook_options[:id]
353
+ hook_data[id] ||= Hash.new
354
+ block.call arg, hook_data[id]
355
+ else
356
+ block.call arg
357
+ end
358
+ rescue => e
359
+ log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
360
+ log_writer.debug e.backtrace.join("\n")
361
+ end
362
+ end
363
+ end
364
+
365
+ def final_options
366
+ options.final_options
367
+ end
368
+
369
+ def self.default_tcp_host
370
+ ipv6_interface_available? ? Const::UNSPECIFIED_IPV6 : Const::UNSPECIFIED_IPV4
371
+ end
372
+
373
+ def self.default_tcp_bind(port = DEFAULTS[:tcp_port])
374
+ URI::Generic.build(scheme: 'tcp', host: default_tcp_host, port: Integer(port)).to_s
375
+ end
376
+
377
+ def self.ipv6_interface_available?
378
+ Socket.getifaddrs.any? do |ifaddr|
379
+ addr = ifaddr.addr
380
+ addr&.ipv6? && !addr&.ipv6_loopback?
381
+ end
382
+ rescue StandardError
383
+ false
384
+ end
385
+
386
+ def self.temp_path
387
+ require 'tmpdir'
388
+
389
+ t = (Time.now.to_f * 1000).to_i
390
+ "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
391
+ end
392
+
393
+ def self.random_token
394
+ require 'securerandom' unless defined?(SecureRandom)
395
+
396
+ SecureRandom.hex(16)
397
+ end
398
+
399
+ private
400
+
401
+ def rewrite_unavailable_ipv6_binds!
402
+ return if self.class.ipv6_interface_available?
403
+
404
+ tried_ipv6_bind = false
405
+ bind_schemes = ['tcp', 'ssl']
406
+
407
+ @_options[:binds] = Array(@_options[:binds]).map do |bind|
408
+ uri = URI.parse(bind)
409
+ next bind unless bind_schemes.include?(uri.scheme)
410
+
411
+ host = uri.host&.delete_prefix('[')&.delete_suffix(']')
412
+ next bind unless host&.include?(':')
413
+
414
+ tried_ipv6_bind = true
415
+ next bind unless host == Const::UNSPECIFIED_IPV6
416
+
417
+ uri.host = Const::UNSPECIFIED_IPV4
418
+ uri.to_s
419
+ rescue URI::InvalidURIError
420
+ bind
421
+ end
422
+
423
+ warn "WARNING: IPv6 bind requested but no non-loopback IPv6 interface was detected" if tried_ipv6_bind
424
+ end
425
+
426
+ def require_processor_counter
427
+ require 'concurrent/utility/processor_counter'
428
+ rescue LoadError
429
+ warn <<~MESSAGE
430
+ WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
431
+ Please add "concurrent-ruby" to your Gemfile.
432
+ MESSAGE
433
+ raise
434
+ end
435
+
436
+ def parse_workers(value)
437
+ if value == :auto || value == 'auto'
438
+ require_processor_counter
439
+ Integer(::Concurrent.available_processor_count)
440
+ else
441
+ Integer(value)
442
+ end
443
+ rescue ArgumentError, TypeError
444
+ raise ArgumentError, "workers must be an Integer or :auto"
445
+ end
446
+
447
+ # Load and use the normal Rack builder if we can, otherwise
448
+ # fallback to our minimal version.
449
+ def rack_builder
450
+ # Load bundler now if we can so that we can pickup rack from
451
+ # a Gemfile
452
+ if @puma_bundler_pruned
453
+ begin
454
+ require 'bundler/setup'
455
+ rescue LoadError
456
+ end
457
+ end
458
+
459
+ begin
460
+ require 'rack'
461
+ require 'rack/builder'
462
+ ::Rack::Builder
463
+ rescue LoadError
464
+ require_relative 'rack/builder'
465
+ Puma::Rack::Builder
466
+ end
467
+ end
468
+
469
+ def load_rackup
470
+ raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
471
+
472
+ rack_app, rack_options = rack_builder.parse_file(rackup)
473
+ rack_options = rack_options || {}
474
+
475
+ options.file_options.merge!(rack_options)
476
+
477
+ config_ru_binds = []
478
+ rack_options.each do |k, v|
479
+ config_ru_binds << v if k.to_s.start_with?("bind")
480
+ end
481
+
482
+ options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
483
+
484
+ rack_app
485
+ end
486
+
487
+ def run_mode_hooks
488
+ workers_before = @_options[:workers]
489
+ key = workers_before > 0 ? :cluster : :single
490
+
491
+ @_options.all_of(key).each(&:call)
492
+
493
+ unless @_options[:workers] == workers_before
494
+ raise "cannot change the number of workers inside a #{key} configuration hook"
495
+ end
496
+ end
497
+
498
+ def set_conditional_default_options
499
+ @_options.default_options[:preload_app] = !@_options[:prune_bundler] &&
500
+ (@_options[:workers] > 1) && Puma.forkable?
501
+ end
502
+
503
+ def warn_hooks
504
+ return if options[:workers] > 0
505
+ return if options[:silence_fork_callback_warning]
506
+
507
+ log_writer = LogWriter.stdio
508
+ @hooks.each_key do |hook|
509
+ options.all_of(hook).each do |hook_options|
510
+ next unless hook_options[:cluster_only]
511
+
512
+ log_writer.log(<<~MSG.tr("\n", " "))
513
+ Warning: The code in the `#{hook}` block will not execute
514
+ in the current Puma configuration. The `#{hook}` block only
515
+ executes in Puma's cluster mode. To fix this, either remove the
516
+ `#{hook}` call or increase Puma's worker count above zero.
517
+ MSG
518
+ end
519
+ end
520
+ end
521
+ end
522
+ end