Library configuration - multi-instance

Completely agree with passing arguments as an always more flexible approach.

Just wanted to comment that on your example it still is a compile time dependency. I quote with my comments:

# config.exs
config :my_lib, MyRepo,
  adapter: Sandbox # value is determined at compile time

defmodule MyRepo do
  defp adapter do
    # Even if next line is called during app boot, it uses a compile time value
    Application.get_env(:my_lib, MyRepo)[:adapter]
  end
end

The only way to have a true runtime (which here means a value provided where the application is run) is by using anything only available at the place where the app is run. This is why I’ve mentioned System.fetch_env but could be something like a configuration provider only available at deployment environment.

In any case, your pattern is a very clear one: the library should receive all of its configuration as parameters and, if there is any process, use the application supervision to get those values. With that we avoid the config.exs where we can. Also, for multiple instances we can use your strategy of having several processes under the supervision tree, each with its own name passed as an argument.

Just as an example (I know I’m verbose… please bear with me…):

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
       {MyLibrary, my_credentials_1()},
       {MyLibrary, my_credentials_2()},
    ]
    # ...
  end

  defp my_credentials_1 do
     [
       name: :my_library_credentials_1,
       # other options
     ]
  end

    defp my_credentials_2 do
     [
       name: :my_library_credentials_2,
       # other options
     ]
  end
end

With that we have:

  • MyApp.Aplication → MyApp.Supervisor
  • MyApp.Superversion → :my_library_credentials_1
  • MyApp.Superversion → :my_library_credentials_2

This seems like the best approach I guess. The library would use calls with names like MyLibrary.some_function(:my_library_credentials_1) and fetch options with that.

I just wonder now if there should be some default name to avoid needing an extra argument when there is only one configuration available. The same example call would then be MyLibrary.some_function() and that would use the :default configuration name as a default argument.

Thanks once again for the discussion!