Libraries can start processes too!

It’s the kind of thing that, if you are used to other languages, would make you very suspicious. Library code starting its own processes — you can almost feel the mess and sense the bugs just musing over it. Yet in Elixir (and, of course, Erlang too), this is a totally normal thing to do.

The Elixir approach to shared mutable state is wrapping it in a process. In this case, I needed a counter and the easiest way to implement it is to use an Agent which is a kind of process designed to handle simple state. In this case, the get_and_update function allows me to return the counter and increment it as an atomic operation.

To start an Agent you use the Agent.start_link function. But where to call it? Do I have to add some equivalent initializer function to my library? While not exactly onerous it felt awkward somehow like my implementation was leaking into the caller. Then again did I have to stop the agent process somewhere? Where would I do that?

Now I figured out how to manage the life-cycle of the agent process myself within the library. But it turns out to be unnecessary. All I had to was make one change to my mix.exs file and one addition to a module in my library.

def application do
  [
    extra_applications: [:logger]
  ]
end

becomes:

def application do
  [
    extra_applications: [:logger],
    mod: {Ergo, []}
  ]
end

along with changing the referenced library module, Ergo to look like:

defmodule Ergo
  use Application

  def start(_type, _args) do
    Supervisor.start_link([Ergo.AgentModule], strategy: :one_for_one)
  end

  …
end

This is enough that any application using my library (called Ergo, btw) knows will automatically start the Agent and manage its life-cycle. Without me, or the calling application, needing to know anything about it at all.

This is a pretty neat trick.

Leave a Reply

Your email address will not be published. Required fields are marked *