Repository: puma/puma
File: lib/puma/configuration.rb (Ruby)

Code before:
  #
  # [Note:]
  #   `:port` and `:host` are not valid keys. By the time they make it to the
  #   configuration options they are expected to be incorporated into a `:binds` key.
  #   Under the hood the DSL maps `port` and `host` calls to `:binds`
  #
  #     config = Configuration.new({}) do |user_config, file_config, default_config|
  #       user_config.port 3003
  #     end
  #     config.load
  #     puts config.options[:port]
  #     # => 3003
  #
  # It is expected that `load` is called on the configuration instance after setting
  # config. This method expands any values in `config_file` and puts them into the
  # correct configuration option hash.
  #
  # Once all configuration is complete it is expected that `clamp` will be called
  # on the instance. This will expand any procs stored under "default" values. This
  # is done because an environment variable may have been modified while loading
  # configuration files.
  class Configuration
    DEFAULTS = {
      auto_trim_time: 30,
      binds: ['tcp://0.0.0.0:9292'.freeze],
      fiber_per_request: ENV["PUMA_FIBER_PER_REQUEST"] == "true",
      debug: false,
      early_hints: nil,
      environment: 'development'.freeze,
      # Number of seconds to wait until we get the first data for the request.
      first_data_timeout: 30,
      # Number of seconds to wait until the next request before shutting down.
      idle_timeout: nil,
      io_selector_backend: :auto,
      log_requests: false,
      logger: STDOUT,
      # How many requests to attempt inline before sending a client back to
      # the reactor to be subject to normal ordering. The idea here is that
      # we amortize the cost of going back to the reactor for a well behaved
      # but very "greedy" client across 10 requests. This prevents a not
      # well behaved client from monopolizing the thread forever.
      max_fast_inline: 10,
      max_threads: Puma.mri? ? 5 : 16,
      min_threads: 0,
      mode: :http,
      mutate_stdout_and_stderr_to_sync_on_write: true,
      out_of_band: [],
      # Number of seconds for another request within a persistent session.
      persistent_timeout: 20,
      queue_requests: true,
      rackup: 'config.ru'.freeze,

Review comment (suggestion):
I poked in our codebase and we don't have the concept of using env var `"true"` for boolean values. My request is that we change this to be truthy/falsey rather than checking a specific key. 

```suggestion
      fiber_per_request: ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
```


Longer:

When it comes to boolean values and env vars, I find that it's simpler to use "anything in here" as true, and `unset` as `false`. Otherwise you end up with people who `export PUMA_FIBER_PER_REQUEST=1` or `PUMA_FIBER_PER_REQUEST=on` or `PUMA_FIBER_PER_REQUEST=enabled` and then they are confused when it doesn't work. 

The first downside is that `PUMA_FIBER_PER_REQUEST=false` (or friends) would evaluate to be "true", but this is not surprising to an experienced rubyist as all env vars are strings and a "false" string is truthy. 

The other downside (is bigger) is that there's no way to over-write a prior value via something like `heroku config` which can only set values or not-set values, it cannot over-write an externally set env var. In practice it's not been a major problem, and so I still recommend truthy/falsey env vars.



Code after:
  #
  # [Note:]
  #   `:port` and `:host` are not valid keys. By the time they make it to the
  #   configuration options they are expected to be incorporated into a `:binds` key.
  #   Under the hood the DSL maps `port` and `host` calls to `:binds`
  #
  #     config = Configuration.new({}) do |user_config, file_config, default_config|
  #       user_config.port 3003
  #     end
  #     config.load
  #     puts config.options[:port]
  #     # => 3003
  #
  # It is expected that `load` is called on the configuration instance after setting
  # config. This method expands any values in `config_file` and puts them into the
  # correct configuration option hash.
  #
  # Once all configuration is complete it is expected that `clamp` will be called
  # on the instance. This will expand any procs stored under "default" values. This
  # is done because an environment variable may have been modified while loading
  # configuration files.
  class Configuration
    DEFAULTS = {
      auto_trim_time: 30,
      binds: ['tcp://0.0.0.0:9292'.freeze],
      fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
      debug: false,
      enable_keep_alives: true,
      early_hints: nil,
      environment: 'development'.freeze,
      # Number of seconds to wait until we get the first data for the request.
      first_data_timeout: 30,
      # Number of seconds to wait until the next request before shutting down.
      idle_timeout: nil,
      io_selector_backend: :auto,
      log_requests: false,
      logger: STDOUT,
      # Limits how many requests a keep alive connection can make.
      # The connection will be closed after it reaches `max_keep_alive`
      # requests.
      max_keep_alive: 25,
      max_threads: Puma.mri? ? 5 : 16,
      min_threads: 0,
      mode: :http,
      mutate_stdout_and_stderr_to_sync_on_write: true,
      out_of_band: [],
      # Number of seconds for another request within a persistent session.
      persistent_timeout: ENV.fetch('PUMA_PERSISTENT_TIMEOUT', 65),
      queue_requests: true,
      rackup: 'config.ru'.freeze,
      raise_exception_on_sigterm: true,