Search code examples
elixirgen-server

Calling a GenServer fails due to an incorrect name


I have this GenServer in a library:

defmodule MyLib.Cache do
  use GenServer

  def start_link([]) do

    IO.puts("****cache genserver, name: #{__MODULE__}")


    # GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
    GenServer.start_link(__MODULE__, %{}, name: MyLibCache)   # no dot
  end
  # [.........]

And this application:

    defmodule MyApp.Application do
      use Application

      def start(_type, _args) do
        import Supervisor.Spec

        children = [
          {Phoenix.PubSub, [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]},
          {MyLib.Repo, []},
          {MyAppWeb.Endpoint, []},
          {MyLib.Cache, []} # notice the dot
        ]
  • Why is it working work when I specify name: MyLibCache (without a dot) although the name must be MyLib.Cache - with a dot?

  • I want to be able to use name: __MODULE__ in the GenServer. But with it, it'll fail to start it in application.ex because it won't find the module with such a name. How to fix it?

update:

error at runtime, only when I try to access a page where Cache is called, that is, not at startup:

exited in: GenServer.call(MyLibCache, {:get, "Elixir.MyLib.Dal.User.2"}, 5000) ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

namely, this will work with no error:

GenServer.start_link(__MODULE__, %{}, name: MyLibCache)
# or 
# GenServer.start_link(__MODULE__, %{}, name: MyLib.Cache) # with dot

this - with the error shown above:

GenServer.start_link(__MODULE__, %{}, name: __MODULE__)

Solution

  • Supervisor.Spec has been deprecated since Elixir 1.5. You do not need to use it. Here a working example:

    defmodule MyLib.Cache do
      use GenServer
    
      def init(state), do: {:ok, state}
    
      def start_link(state) do
        GenServer.start_link(__MODULE__, state, name: __MODULE__)
      end
    end
    

    Then in application.ex:

    def start(_type, _args) do
      children = [
        MyLib.Cache
      ]
    
      opts = [strategy: :one_for_one, name: MyApp.Supervisor]
      Supervisor.start_link(children, opts)
    end
    

    Why is it working work when I specify name: MyLibCache (without a dot) although the name must be MyLib.Cache - with a dot?

    The name argument to GenServer.start_link/3 is the name of the server, not the module. They can be the same, but they don't have to be. The name you supply here is the name that needs to be supplied to Genserver.call/3 later. See Name registration for details.