It’s very easy to supervise :simple_one_for_one
children with Registry. The Registry is unique, and via
tuple works very good.
But the question is: How to dispatch to all these children?
It seems to me, that is possible to dispatch only to duplicate registry!
Why it’s not possible to list all registered in Registry pid’s?
The workaround is - using Supervisor.which_children
get all pids and dispatch messages to them. But it looks a bit rusty.
Have you taken a look at the Using as a dispatcher section of the documentation? If that still doesn’t answer your question, can you give a bit more information about what you are trying to do?
You could use Registry.match/3 for that:
Registry.start_link(:unique, MyRegistry)
Registry.register(MyRegistry, :foo, nil)
spawn(fn -> Registry.register(MyRegistry, :bar, nil); :timer.sleep(:infinity) end)
Registry.match(MyRegistry, :_, :_)
# [{#PID<0.80.0>, nil}, {#PID<0.86.0>, nil}]
However, I feel that it’s better to have another (:duplicate
) registry for dispatching. The unique registry should be used when you want to find a particular process which plays some role in your system. The duplicate registry should be used when you want to dispatch to a group of processes. Those are two different needs, so I believe that using different registries describes the idea more explicitly. For what it’s worth, this is how I’d do it myself. If a process needs to be uniquely found, but also belongs to some process group, I’d register it with two registries.
Two registeries is great idea as for me from the point of good architect. I thought about it.
But the problem is with consistency:
Registration in duplicate
registry is doing manualy, as I understand. For example, in init
function:
def init(_) do
Registry.register(MyRegistry, "worker_class_name", "my_worker_name")
end
But if the supervisor restarts the simple_one_for_one
worker after failure, PID
is updated in only uniq
register.
So, as I understand, init
should be rewrited in such manner:
def init(_) do
# check here, that registry already have entry with such name, and if not
Registry.register(MyRegistry, "worker_class_name", "my_worker_name")
# and if yes - firstly remove that entry, but hard to understand how, and then
Registry.register(MyRegistry, "worker_class_name", "my_worker_name")
end
So, may be there are some recipes of doing this already? Or may be Registry
need some additional functionality? Or even, may be my approach is totally wrong.
It’s going to work fine for both registries. If the process terminates, it’s deregistered from all the registries. When the new process is started, it will be properly registered with both registries. You don’t need to check whether the process is already registered, nor remove it from the registry manually.
2 Likes