What are some best practices around writing libraries in Elixir ?

Hi there

I am trying to write a library in Elixir. I just read the guide here and I feel that I do not understand if it is possible or even recommended to have a library that does not have an Application but instead has a supervision tree that should be started by the calling (user’s) application.

For example, when I created a simple library without an Application at the top level and instead had a supervision tree using just a Supervior that I expected to start when calling from iex by calling
Supservisor.start_child(MySupervisor, strategy: :one_for_one) , I got the following error

no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

I would be thankful to you if someone could kindly take a look and help me with this. Thank you very much.

2 Likes

Hello, welcome to the forum,

Are You sure You want to use start_child? It would mean the supervisor is already started, and You try to start child.

Maybe You can try start_link to start the supervisor first?

Anyway You can omit --sup if You don’t want application, or have an application that starts nothing, and You start it manually, when creating a project with mix

1 Like

Take a look at ecto, as far as I remember it doesn’t start anything on its own, but insteaf provides you the tools to have as many repositories under your supervision.

1 Like

Welcome to the forum. It’s perfectly fine to provide a library that starts it own application and supervision tree. But there are a few things to be aware of.

Applications are singletons. So if multiple libraries depend on your application only 1 of your application will be started. This means that any configuration of your library is global. That might be an OK tradeoff for your purposes.

If that tradeoff isn’t acceptable then you can provide a module and supervision tree that users can add to their applications supervision tree. This can be a little tricky especially if you have multiple named processes that you’re starting in your tree. Because you’re letting the end user start these processes you’ll need to make sure that they can pass a unique name in and you’ll need to use that unique name as a way to identify any named children processes. If you don’t do this and use a single unique name then you’ll have collisions and you won’t be able to start multiple versions of your library which invalidates the reason for providing your library in this way instead of as an application.

4 Likes

Additionally, this has been posted recently as a part of the Elixir 1.9.0 announcement:

https://hexdocs.pm/elixir/library-guidelines.html#avoid-application-configuration

:+1: here.

Application supervisor’s direct children are not dynamic. f you want to spin up new process by caller, you have two ways

  • Option 1: expose API to start new process under the library’s supervision tree (e.g. MyLibrary > MyLibrary.Supervisor > MyLibrary.DynamicSupervisor > (new) MyLibrary.Process1)
  • Option 2: provide an module to caller to manage the process by itself (e.g. `YourApp > YourApp.Supervisor > MyLibrary.Process)

There is no right answer, but I prefer to expose those behavior explicitly to caller.

Thanks everyone for help…