Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the benefit of registering name using {:via, module, term} in GenServer.start_link/3?

In GenServer.start_link/3 I can register a name locally using an atom for a process like this:

defmodule Worker do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, nil, name: :worker)
  end
end

Then I can start a supervisor to supervise this process:

defmodule Boss do
  use Supervisor

  def init(_) do
    children = [worker(Worker, [])]
    supervise(children, strategy: :one_for_one)
  end
end

Now I want to make the supervisor to supervise 3 Worker processes, so I need to give those 3 processes unique names, so that when supervisor restarts the process it will always use the same symbolic name.

I can simply use string interpolation for the unique Worker process name like this:

defmodule Worker do
  use GenServer

  def start_link(id) do
    GenServer.start_link(__MODULE__, nil, name: :"worker_#{id}")
  end
end

Then supervise 3 processes like this:

defmodule Boss do
  use Supervisor

  def init(_) do
    children = for id <- 1..3 do
      worker(Worker, [id], id: id)
    end
    supervise(children, strategy: :one_for_one)
  end
end

It works like expected.

In the doc for GenServer under "Name registration" section, it says you can use {:via, module, term} to register a name as well.

{:via, module, term} - the GenServer is registered with the given mechanism and name. The :via option expects a module that exports register_name/2, unregister_name/1, whereis_name/1, and send/2. One such example is the :global module which uses these functions for keeping the list of names of processes and their associated PIDs that are available globally for a network of Elixir nodes. Elixir also ships with a local, decentralized and scalable registry called Registry for locally storing names that are generated dynamically.

However, in order to use :via option you have to implement a module that exports register_name/2, unregister_name/1, whereis_name/1 and send/2, which seems pretty cumbersome comparing to simply use string interpolation technique as shown above.

So my question is:

  1. What's the benefit of registering name using {:via, module, term} over simply using string interpolation?
  2. Is there a pragmatic example of using :via option to register name?
like image 983
sbs Avatar asked Aug 18 '16 07:08

sbs


People also ask

What is GenServer?

Settings View Source GenServer behaviour (Elixir v1. 13.4) A behaviour module for implementing the server of a client-server relation. A GenServer is a process like any other Elixir process and it can be used to keep state, execute code asynchronously and so on.

What is a registry Elixir?

12.3) A local, decentralized and scalable key-value process storage. It allows developers to lookup one or more processes with a given key. If the registry has :unique keys, a key points to 0 or 1 process.

What is OTP Elixir?

What are Elixir and OTP? Elixir is a functional programming language built on the Erlang VM. OTP is a process oriented programming framework integral to Erlang and Elixir.

Does start_link/3 support the genserver to register a name?

Both start_link/3 and start/3 support the GenServer to register a name on start via the :name option. Registered names are also automatically cleaned up on termination. The supported values are: an atom - the GenServer is registered locally with the given name using Process.register/2.

What is the genserver registered with?

{:via, module, term} - the GenServer is registered with the given mechanism and name. The first option, an atom, is what we have been using so far and we know it’s not enough for our needs now. The second option is used to register a process globally, across multiple nodes, and relies on a local ETS table.

What are the supported values for the genserver?

The supported values are: an atom - the GenServer is registered locally with the given name using Process.register/2. {:global, term} - the GenServer is registered globally with the given term using the functions in the :global module. {:via, module, term} - the GenServer is registered with the given mechanism and name.

Why use a generic server process (genserver)?

The advantage of using a generic server process (GenServer) implemented using this module is that it will have a standard set of interface functions and include functionality for tracing and error reporting. It will also fit into a supervision tree. The GenServer behaviour abstracts the common client-server interaction.


1 Answers

tl;dr - :via is there to allow you to use non-standard process registration libraries. They must conform to an interface (much like implementing an interface in Java), and may provide extra functionality.

The main example is when you want to use a non-standard name registration library. Take for example the gproc library. It follows the interface requirements to use :via, so minimal intrusion is required into your application code. In addition, it provides several advantages over the standard name registration system:

  1. Use any term as a process alias
  2. Register a process under several aliases
  3. Non-unique properties can be registered simultaneously by many processes; query level comprehension (QLC) and match specification interface for efficient queries on the dictionary
  4. Await registration, let's you wait until a process registers itself
  5. Atomically give away registered names and properties to another process
  6. Counters, and aggregated counters, which automatically maintain the total of all counters with a given name
  7. Global registry, with all the above functions applied to a network of nodes

Elixir's Registry module is another example of one which requires a via tuple.

like image 100
Cody Poll Avatar answered Sep 23 '22 08:09

Cody Poll