victorolinasc
Library configuration - multi-instance
Hello people!
I am about to write a “SDK” for a service. Before I got started, I was looking for some general patterns and best practices.
One thing I noticed is that most of them don’t worry about multiple “instances”. Almost all of them that I’ve used or have seen are using the single instance approach. By that I mean: they have a config like:
# Configuration
config :my_library, client_id: id, client_key: key
defmodule MyApplication do
# possibly add MyLibrary to the application supervision
end
# Then on application code
MyLibrary.make_some_call(params)
Examples: :ex_aws, :ex_twilio, :sendgrid, etc…
Ecto uses a different approach that facilitates the multiple instances approach but it makes it a bit more verbose to configure it.
# Configuration
config :my_app, MyRepo1, options
config :my_app, MyRepo2, other_options
defmodule MyRepo1 do
use Ecto.Repo, opts # where otp_app: :my_app
end
defmodule MyRepo2 do
use Ecto.Repo, opts # where otp_app: :my_app
end
defmodule MyApplication do
# add MyRepo1 and MyRepo2 to the application supervision
end
# Then on application code
some_query |> MyRepo1.all()
some_query |> MyRepo2.all()
With the first approach, I don’t think there is a good way to have two instances of the library running at the same time. With the second approach we end up needing some macros…
I would like to hear people’s opinion on this:
- Should we, as library authors, strive to always provide a multi-instance configuration?
- Are there other ways to do this cleanly? Even if that demands Elixir 1.9+…
Cheers!
Most Liked
keathley
Generally, libraries shouldn’t rely on application env at all. A lot of libraries continue to use that pattern because it was popular in the early days of Elixir. But its a bad model and shouldn’t be copied. If your library needs to use processes, then users should be able to pass in arguments when they start the process in their supervisor. Redix is an excellent example of how to do this well.
There are exceptions to this rule. Sometimes it makes the most sense to provide a full-blown OTP Application. I typically do this because there’s nothing in the application to configure, the supervision hierarchy is complex, or if there’s no benefit to the user managing the lifecycle of the process.
Building a library that is re-usable without collisions is often much more difficult. But I think it pays off in the long run.








