How to specifiy location of DETS table files for a library

I’m writing a Bloomberg terminal API library for Elixir, and this library will need to store some mutable startup configuration in a DETS table. Specifically, ticker streams that are subscribed to during a session can (optionally) be stored, reloaded the next time a session is started, and resubscribed-to.

So now I need a file location for the DETS table. I could force one on users for example ~/.lib_name/application_name_subs.dets, but it seems right to be able to allow users to override such a location.

Problem is the library guidelines says one should avoid application-level configuration.

But in the case I mention, I’m going to guess application level configuration for such an override option is okay? What are the alternatives for the above?

Where in the code is a session “started”? That’s where I’d start looking for a place to supply config.

For instance, here’s how Oban does it (from the installation guide):

# config/config.exs
config :my_app, Oban,
  repo: MyApp.Repo,
  plugins: [Oban.Plugins.Pruner],
  queues: [default: 10]

# lib/my_app/application.ex
def start(_type, _args) do
  children = [
    MyApp.Repo,
    {Oban, Application.fetch_env!(:my_app, Oban)}
  ]

  Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
1 Like

Yeah so basically Oban is using global application configuration file?

Nope, see how it’s scoped under your app? And even that is a convention, you can just supply config directly to the child and skip the app env entirely.

1 Like

The difference is small but important:

# avoid this
config :somebody_elses_library, foo: "bar"

# and in the supervisor
SomebodyElsesLibrary

(or not mentioned in the application supervisor at all and started via `extra_applications` etc)

--------------------------

# do this
config :my_app, SomebodyElsesLibrary, foo: "bar"

# and in the supervisor
{SomebodyElsesLibrary, Application.fetch_env!(:my_app, SomebodyElsesLibrary)}

A good way to check if you’re on the right path is to ask “can there be two of them?”

  • in the “don’t” case, there’s nowhere for that second config to go. Back when umbrella apps had separate config directories per-app, people would try to configure the same app differently in different child apps only to discover that all the app configs were always loaded

  • in the “do” case, all it takes is more of the same:

config :my_app, SomebodyElsesLibrary, foo: "bar"
config :my_app, SomebodyElsesLibraryWithBellsOn, foo: "bar with bells on", name: WithBellsOn

# and in the supervisor
{SomebodyElsesLibrary, Application.fetch_env!(:my_app, SomebodyElsesLibrary)},
{SomebodyElsesLibrary, Application.fetch_env!(:my_app, SomebodyElsesLibraryWithBellsOn)},
2 Likes