Naming GenServer using :via does not work the same as naming Agent with :via

I’m working with a custom registry and I’ve noticed that it doesn’t seem to like GenServers. Whereas I can start up an Agent using the same :via clause and things work.

Given this GenServer:

defmodule Replay do
    @moduledoc false
    use GenServer

    @impl true
    def init(opts), do: {:ok, opts}

    @impl true
    def handle_call(request, _from, state), do: {:reply, request, state}
end

I try starting instances of it:

{:ok, _} = Registry.start_link(keys: :unique, name: MyRegistry)
{:ok, _pid} = GenServer.start_link(Replay, name: {:via, Registry, {MyRegistry, "aaa", "v1"}})
{:ok, _pid} = GenServer.start_link(Replay, name: {:via, Registry, {MyRegistry, "ccc", "v3"}})
{:ok, _pid} = GenServer.start_link(Replay, name: {:via, Registry, {MyRegistry, "bbb", "v2"}})
{:ok, _pid} = Agent.start_link(fn -> 0 end, name: {:via, Registry, {MyRegistry, "ddd", "v4"}})
Registry.select(MyRegistry, [{{:"$1", :"$2", :"$3"}, [], [{{:"$1", :"$2", :"$3"}}]}])

# Expected:
[{"aaa", #PID<0.131.0>, "v4"}, {"bbb", #PID<0.132.0>, "v4"}, {"ccc", #PID<0.133.0>, "v4"}, {"ddd", #PID<0.134.0>, "v4"}]

# Actual:
[{"ddd", #PID<0.134.0>, "v4"}]

Can someone explain this? And hopefully point at the error? Thanks in advance!

I think this should work, but as a sanity check: Are all processes still alive at this point?

yes, Process.alive?/1 returns true. :thinking:

This is passing name: ... to Replay as opts, GenServer.start_link/3 always needs a second argument. You likely want:

{:ok, _pid} = GenServer.start_link(Replay, [], name: {:via, Registry, {MyRegistry, "aaa", "v1"}})
8 Likes

Matt, you have saved my sanity: you are exactly right. I fell into a copy-pasta trap and did not notice my mistake. Thank you!!!