如何通过注册儿童获得注册的密钥(pids)

时间:2017-02-07 09:33:29

标签: elixir

我想使用Registry模块来注册动态创建的子进程。 所以我在我的主管树中添加了注册表:

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

儿童注册的情况如下:

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

所以,我的问题是 - 如何在我的注册表中获取所有密钥(儿童pids)。 我尝试使用Registry.keys\2,但没有成功。

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

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

这有点晚了,但我自己也遇到过这个问题。似乎没有正式的方法可以做到这一点,但是挖掘Registry来源并阅读有关:erts的内容我提出了以下解决方案:

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

答案 1 :(得分:0)

如果我理解正确,则需要从给定的Registry中提取所有注册的密钥。

自Elixir 1.9.0起,可以通过Registry.select/2实现以下目的:

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

这将返回所有已知键的列表。

有关此功能的更多信息,请参见Hexdocs上Registry.select/2的规范。