GenServer and how to access options in callback functions

I can pass options like so:

def start_link(opts) do
  GenServer.start_link(__MODULE__, opts)
end

def init(opts) do
  {:ok, %{}}
end

def handle_info(:work, state) do # how do I get the options?
  # do something
  {:noreply, state}
end

But what is the best way to access the options in Genserver callbacks such as handle_info/2?

Putting the options into the state will lead to mixing state and options.

For an example of such option: a given custom callback function to call on some condition inside handle_info/2.

You could argue that this is mixing state and options, or you could argue that options are part of the state.

I’m personally comfortable with organising my state along the lines of %{opts: opts, data: data} where the “dynamic” part is separated from the more static part. This is absolutely the easiest way to debug your functions, and also put test harnesses around, as there is no reliance on external state/magic side effects.

If you really don’t like that, you could do one of the following:

If the options relate to all instances of your GenServer, you could look them up from application settings each time - I’m not sure how performant the app settings lookup is.

Use Process.put to squirrel stuff away on init and retrieve it with Process.get. This is rarely used - see Is Process.put safe comparing to passing attrs for all the downsides.

Use a private ETS table (i.e. one that can only be read from the process that created it). I would guess similar comments apply.

1 Like

You could (in principle, it may not make sense in your specific domain) call that GenServer with a message like {:set_custom_callback, some_function} to change the value at runtime. The custom callback function is part of the state.

The ‘state’ is what you choose to make it. I definitely prefer to refer to it as the ‘data’ to make this more explicit. Keeping the options in the data is definitely the easiest and most explicit way of doing it.

3 Likes

^ This is about the most authoritative response you’re going to get on whether or not it’s “okay” to mix options and state. :smile: