79327646

Date: 2025-01-03 20:50:16
Score: 0.5
Natty:
Report link

To directly answer your question, the problem is in the {:ok, _storage} = Supervisor.start_child(supervisor, {Usersystem.Storage, name: {:via, Registry, {Usersystem.Registry, "storage"}}}). First, there is no name in child_spec, the closest field you might find is the id, but it also does not solve your issue, since this id is local to the supervisor. Your tuple is valid enough for starting the supervisor, but the {:via, Registry, _} does not mean registering it in the registry table. You need to add this tuple to the Usersystem.Storage server instead:

defmodule Stackoverflow do
  require Logger

  def start() do
    opts = [strategy: :one_for_one, name: Usersystem.Supervisor]

    {:ok, supervisor} = Supervisor.start_link([], opts)

    # The supervisor starts a registry table, which can be used by servers later
    {:ok, _} =
      Supervisor.start_child(supervisor, {Registry, keys: :unique, name: Usersystem.Registry})

    {:ok, _storage} =
      Supervisor.start_child(
        supervisor,
        # A map child spec, check https://hexdocs.pm/elixir/1.12/Supervisor.html#child_spec/2
        %{
          # {Module callback, function callback from module, params to the function (in this case ignored)}
          start: {Usersystem.Storage, :start_link, [:ok]},
          # This id is internal to the supervisor, it is only recognizable under `Usersystem.Supervisor`
          id: :storage
        }
      )

    # I did not imported Plug.Cowboy since this example does not need it
    # {:ok, _router} = Supervisor.start_child(supervisor, {Plug.Cowboy, scheme: :http, plug: Usersystem.Router, options: [port: 8080] })

    res = Registry.lookup(Usersystem.Registry, "storage")

    sup_children = Supervisor.which_children(Usersystem.Supervisor)

    Logger.info("registry response: #{inspect(res)}")
    # [info] registry response: [{#PID<0.149.0>, nil}]

    # I will not log the long response, but note how the supervisor logs the storage child with the `:storage` id we provided
    Logger.info("Supervisors children response: #{inspect(sup_children)}")

    {:ok, supervisor}
  end
end

defmodule Usersystem.Storage do
  use GenServer

  def start_link(_) do
    # This will register the server properly in the Usersystem.Registry table under "storage"
    GenServer.start_link(__MODULE__, [], name: {:via, Registry, {Usersystem.Registry, "storage"}})
  end

  def init(_), do: {:ok, nil}
end

However, if you have only one storage server, maybe you don't even need the Registry. instead of GenServer.start_link(__MODULE__, [], name: {:via, Registry, {Usersystem.Registry, "storage"}}), you could just do GenServer.start_link(__MODULE__, [], name: :my_storage_server. Which makes the server start under the atom name you provided. Note that you could name this as :storage and it would not conflict with the supervisor child id also called :storage at all, since the sup id is internal, I'm just using a different name to make this example clearer. You can verify the name is reachable, by simply starting the supervisor and typing: Process.where_is(:my_storage_server), which will return the id of your server. When your server restarts, it will be registered under the same atom name, so it will be available without knowing its pid. Since it is a genserver, any process calling the GenServer.call/cast passing the my_storage_server as first parameter will find the storage server.

Some notes:

Reasons:
  • Blacklisted phrase (1): Stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Gabriel Gonçalves Blankenburg