Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get keys (pids) of registered via Register children

Tags:

elixir

I want to use Registry module to register dynamically created children processes. So I added registry into my supervisor tree:

def init([]) do
  children = [
    supervisor(Registry, [:unique, :my_registry]),
    supervisor(MyManager, []),
    # ...
  ]
  opts = [strategy: :one_for_one, name: MySupervisor]
  supervise(children, opts)
end

Registration of children happens like this:

def start_link(%{id: id}) do
  GenServer.start_link(__MODULE__, [], name: {:via, Registry, {:my_registry, id}})
end

So, my questions is – how to get all keys (children pids) in my Registry. I tried to use Registry.keys\2, but without success.

def get_registry_pid do
  Supervisor.which_children(MySupervisor)
  |> Enum.filter(fn {id, _, _, _} -> id == Registry end)
  |> List.first
  |> elem(1) # get a Regisry pid from a tuple {id, pid, type, modules}
end
Registry.keys(:my_registry, get_registry_pid()) # returns []
# but 
Registry.lookup(:my_registry, id) # returns PID as expected

Thanks in advance for any help!

like image 517
Dmitry Avatar asked Feb 07 '17 09:02

Dmitry


2 Answers

This is a little late but I just came across this issue myself. There seems to be no official way to do this but digging through the Registry source and reading something about :erts I came up with the following solution:

defmodule MyApp.Sensor.Registry do
  @doc """
  Lists all the registered sensors from the registry.
  """
  @spec list_sensors!(module) :: [{String.t(), pid, any}]
  def list_sensors!(registry \\ __MODULE__) do
    try do
      # The args for `lookup_element` are taken from the private function
      # `info/1` from the `Registry` module.
      {_kind, _partitions, table, _pid_ets, _} =
        :ets.lookup_element(registry, -1, 2)

      # select_all is the result of `:ets.fun2ms(&(&1))` which works from iex
      # but not when compiled for reasons beyond my comprehension
      select_all = [{:"$1", [], [:"$1"]}]
      :ets.select(table, select_all)
    catch
      :error, :badarg ->
        raise ArgumentError, "#{inspect(registry)} is not running"
    end
  end
end
like image 150
goodkat Avatar answered Oct 19 '22 19:10

goodkat


If I understand correctly, you need to extract all registered keys from a given Registry.

Since Elixir 1.9.0 this can be achieved via Registry.select/2 as follows:

Registry.select(your_registry, [{{:"$1", :_, :_}, [], [:"$1"]}])

This will return the list of all known keys.

For more information on this function, here are the specs of Registry.select/2 on Hexdocs.

like image 3
Nirro Avatar answered Oct 19 '22 19:10

Nirro