BoxTurtle.Runtime.Config (BoxTurtle v0.1.0)

Copy Markdown View Source

Loads a runtime configuration script (standard import Config syntax, read with Config.Reader) into the application environment. Combine with BoxTurtle.Runtime.Config.Helper to get properly typed values from environment variables.

After load_runtime_config/1 runs, the script's settings are read with the usual Application functions, just like compile-time config. Unlike Mix's own config/runtime.exs, the script can live anywhere (for example /etc/my_app/settings.exs beside a release) and can be loaded again later.

Usage

  1. Write the settings script. Give it a name other than config/runtime.exs, which Mix and releases already load by themselves:

    # config/settings.exs
    import Config
    alias BoxTurtle.Runtime.Config.Helper
    
    config :my_app,
      pool_size: Helper.get_env("POOL_SIZE", type: :integer, default: 10),
      feature_flags: Helper.get_env("FEATURE_FLAGS", type: :list, subtype: :atom, default: [])
  2. Point each build at its script. Relative paths are resolved from the current working directory:

    # config/dev.exs
    config :my_app, runtime_config_file: "config/settings.exs"
    
    # config/test.exs
    config :my_app, runtime_config_file: "test/support/settings.exs"
    
    # config/prod.exs
    config :my_app, runtime_config_file: "/etc/my_app/settings.exs"
  3. Load it before starting anything that reads those settings:

    defmodule MyApp.Application do
      use Application
    
      @impl true
      def start(_type, _args) do
        :ok = BoxTurtle.Runtime.Config.load_runtime_config(:my_app)
    
        children = [{MyApp.Pool, size: Application.fetch_env!(:my_app, :pool_size)}]
        Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
      end
    end

Only non-nil values replace existing settings, so an unset environment variable without a :default keeps the compile-time value.

To load a specific file instead, pass its path: load_runtime_config("/etc/my_app/settings.exs").

Summary

Functions

Logs an inspection of the given value, optionally preceded by a message, and returns the value unchanged. Used to place inspections in the midst of a chain of piped calls.

Load runtime config from environment variables and express them as Application-accessible values.

Functions

debug(val, message \\ nil, opts \\ [])

@spec debug(any(), String.t() | nil, keyword()) :: any()

Logs an inspection of the given value, optionally preceded by a message, and returns the value unchanged. Used to place inspections in the midst of a chain of piped calls.

Nothing is logged unless this module is listed in the application's :debug_enabled_modules setting.

Options

  • :condition - a function/1 receiving the value; the message is only logged when it returns true. Useful for throttling messages in highly repetitive code (log only a given id, a matching name, etc.).

Examples

# Inside a module that does `use BoxTurtle.Debug.PipeDebug` and is listed in
# config :my_app, debug_enabled_modules: [...]
%{jazz: "Art", messenger: "Blakey"}
|> Map.values()
|> debug("Jazz Message")          # logs: Jazz Message: ["Art", "Blakey"]
|> Enum.reverse()                 # returns ["Blakey", "Art"]

load_runtime_config(application)

@spec load_runtime_config(atom() | String.t()) :: :ok

Load runtime config from environment variables and express them as Application-accessible values.

Loading a runtime config will replace existing values set during compile time if given the same names.

Parameters

  • application - the Application atom whose runtime configuration is to be set. OR
  • config_path - the path to a runtime script file to parse and load.

Returns

:ok