What is the purpose of naming a GenServer Process?

What is the purpose of naming a GenServer Process, ?

when we can’t even call(send/receive) that process by its name?

Maybe I’m not understanding the question, but why do you say you can’t call it by its name?

defmodule Foo do
  use GenServer

  def start_link([]) do
    GenServer.start_link(__MODULE__, [], name: :whatever_name_you_want)
  end

  def handle_call(:hi, _, state) do
    IO.puts "Oh hi"

    {:reply, state, state}
  end
end

iex> Foo.start_link([])
{:ok, #PID<0.139.0>}
iex> GenServer.call(:whatever_name_you_want, :hi)
Oh hi
[]
2 Likes

Hi you mean that I can Make a perfectly normal call to a process by its name using ,

GenServer.call/cast/multicast.(:process_name, {message})

A six year elixir veteran told me I can’t :frowning:

Maybe there is more context around their “can’t”. You definitely can, though it’s often not a good idea since it essentially makes the process a singleton.

1 Like

But I can spawn several process with that same functionality , by keeping the track of them via their name helping what purpose is they are serving for.
Example: Cache
user cache, cookie cache ,etc a hypothetical example

Calling a GenServer process by it module name also makes it singleton no?

You can’t spawn several processes if you give it a name (although maybe there is a way I don’t know because I’m not an expert). Using my previous example:

iex> Foo.start_link([])
{:ok, #PID<0.139.0>}
iex> Foo.start_link([])
{:error, {:already_started, #PID<0.139.0>}}

I actually can’t give you a good example of when you would want to do this in a large system other than places you’d want some shared global state, although for that I’d likely use ETS. I’m currently using a named GenServer in production as a small part of our CI pipeline. It’s just a paired down logger for use in our release tasks (data migrations) allowing task scripts to simply call a log/1 function without having to pass it a pid.

Otherwise, it’s highly possible (or probable) that I’m not quite qualified enough to give you a satisfying answer! :slight_smile:

And yes, calling it by its module name is the same thing. Although be careful there are you still have to explicitly name it after the module name. They technically aren’t related.

2 Likes

NO no. No worries. Thank you for taking time answer my query :).
My other Q is.
But how to maintain a global state , over shared distributed system,??and How to modify that?

1 Like

That I am definitely not qualified to answer! I could give you a flowery, “I hear this is possible with X or Y!” but I really don’t like doing that :sweat_smile: We only scratch the surface of OTP at work and we are a pretty small so I have no real life experience to draw on there.

2 Likes

You can do this if you have a static list of cache processes you want to start with shared functionality. If you have a more dynamic list of processes, technically you can dynamically give them atom names, but consider it a bad idea. You can use Registry in that case instead.

defmodule Cache do
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: opts[:name])
  end

  # shared cache implementation....
end

children = [
  {Cache, name: :user_cache},
  {Cache, name: :cookie_cache},
  {Cache, name: :etc_cache}
]

Supervisor.start_link(children, strategy: :one_for_one)

GenServer.cast(:user_cache, ...)
GenServer.cast(:cookie_cache, ....)

Though all these cache processes are themselves singletons, even though you can have many with the same functionality. The can each be their own bottleneck, and you may want to explore ETS or a caching library instead.

Global distributed state is trickier, there are a few libraries out there that use things like CRDT or the RAFT protocol. One I came across on the forum today is ram. There are others but I couldn’t list them all for you

1 Like

If you have specific use cases for global state that you can share, maybe someone can offer a more concrete suggestion

If you’ve ever used a database then you’re familiar with at least one way: You use a different system to ensure consistency. If you want to maintain global state within your own application, there are a variety of options but they all depend on the state itself, and whether you’re OK trading off availability or consistency.

I would work very hard to avoid needing to manage global state within my own application.

3 Likes

There is no easy answer to this, but a simple zero order solution is to use the :global module to make the name a cluster-global name and have it be a global singleton process. You will have to think harder about recovery strategies if the node goes down.

For example, one strategy might be: each node detects if the global singleton has gone down and in response triggers spawning a new global instance of the singleton, and if there’s a race, the first one wins.

Oh right—you can name them from the child spec, a-doi!

1 Like

Not sure that my answer is obvious but one reason for using (calling) a process by its name instead of using the Pid is, if you have started a GenServer as a permanent service (singleton), that it might crash and then be restarted with a new Pid by the supervisor. The name will be the same though. Actually “let it crash” is what you expect from a process in Erlang/Elixir that is developed in a non-defensive manner.
For alternatives to the Registry the Erlang gproc library could be a candidate. I don’t know if there are any Elixir wrappers or implementations for it.

A lot has been said already but I feel like a full answer was still missing. Here it goes:

The main reason to name a process is to be able to refer to it later with the given name.
For that reason exactly, you can call a process with that name.
The core idea is as follows: If the original process ever dies and is restarted, processes that know the name are able to find/use the new process without having to manually manage the PIDs (being notified of the restart, cleaning up the old PID and storing the new PID) that would otherwise be required.

If a single name is not good enough (for reasons of scalability or fault-tolerancy, or because you want to use non-atom names), you can move from a single locally-registered process to a globally-registered process or to using a group of processes that are listed together in a Registry.

Also see this section of the GenServer moduledocs about name registration.

4 Likes

I would add LYSE for complementing :slight_smile:

1 Like