Where to do setup logic in a library?


I have an application that uses a queuing system, called jobs:

At its simplest:

> jobs.add_queue(:myqueue, [{:standard_rate, 10}])
> jobs.run(:myqueue, fn -> :httpc.request('https://www.elixirforum.com') end)

Makes at most 10 requests/sec.
As you will have noticed, before using the jobs.run I first need to run jobs.add_queue. This is a setup requirement.


In the newest versions of elixir, when we create a project, it is a library, in the sense that it does not have an application.ex and it lacks a supervision tree (iirc).

So it is a simple functional library. So, what happens when you create new project (library) that has a dependency that needs setup?

Where to put setup?

The application.ex file is a nice place to put the setup of all your dependencies, however, by doing this you are forcing your project to have a supervision tree even if it does not need one, because it is a simple library with some side effects.

So, what do you do then? How do you guys fix this?

Either let the user of the library deal with the setup and accept e.g. a pid or whatever identifier to it as parameters or your library does it and is no longer stateless by a matter of fact and you can simply add applications.ex.

You need to return a process, which indicates the lifecycle of the application. It could be a simple process/genserver, which uses hibernation as soon as started, if one is actually that concerned about resource usage. If not a supervisor without children will do as well.

Is this seen as a good practice within the community ?

It’s how the beam knows an application crashes; by observing the root level process. It’s a requirement of Application.start/2.

If it is really, truly accurate that the library in question has no need for any supervision tree, and the library it wraps handles its own tree, I would provide a pure function as a convenience. It would do the setup steps without any use of Application.ensure_all_started, and then I’d document that users of my library need to call that in their own application startup logic At the appropriate time. The Mix dependency relationships should automatically result in the wrapped library being started first before the end-user OTP app.