Hi everyone, what are the tradeoffs in running a single Registry
(or
a few Registries
) vs. many Registries
? I’ve found that right now,
due to using via_tuples
on kinds of processes that each had their
set of ids, I’ve been creating one Registry
per kind of process. Now
I’m looking at what it would mean for multiple kinds of processes
under a single key, for instance, and I’m wondering if I should keep
on starting a single Registry per purpose or if “a god Registry” is an
acceptable idea… I’m aware this is a strangely open question, so I can provide more details on my specific scenario if you’re interested…
If you are using it within the same application, a single registry is reasonable, given you can “namespace” the keys, such as {:foo, 1}
, {:bar, 1}
, etc.
Hmm. Okay.
I did a little bit of testing. I use a via tuple
to register processes, and so that would mean I would need to pass the module name in the via_tuple, something like
def via_tuple(id) do
{:via, Registry, {MyRegistry, {__MODULE__, id}}}
end
And it’s not necessarily a huge change, I mean, in my first attempt at passing more varied objects through my system, I ended up with this:
def arrive(new_location, {{module, id}, public_info}, from) do
GenServer.call(via_tuple(new_location), {:arrive, {{module, id}, public_info}, from})
end
def handle_call({:arrive, {{module, mob_id}, public_info}, from_loc}, _from, state) do
state.entities
|> Map.keys
|> Enum.each(fn({module, id}) ->
Kernel.apply(module, :handle, [id, {:arrive, public_info, from_loc}]) end)
{:reply, :ok, %Location{state | entities: Map.put(state.entities, {module, mob_id}, public_info)}}
end
The impetus for the question is this kind of complex and ugly pipeline where I send a message to a bunch of modules (eventually all of those will have the same Behaviour
), and now that I have this basic proof-of-concept working, it seems like pub-sub might be a good approach here, I just don’t know if using the Registry for said pub-sub would be a good idea…
Is this making any sense?
I think it makes sense, but I would suggest using a duplicate registry to get the equivalent of process groups. Then you can register all of them under a single name (“mobs” or “entities” or whatever they are) and dispatch to that. Or create groups if you need to. I think you don’t need the “arrive” function either - just send the message directly and process it in handle_info. See:
https://hexdocs.pm/elixir/master/Registry.html#module-using-as-a-pubsub
https://hexdocs.pm/elixir/master/GenServer.html#module-receiving-regular-messages
Well, now we’re getting to some interesting questions about intent!
- I do need the
arrive
function because it does something; it changes the state of the process (and I need this for more than just broadcasting purposes) - Maybe the
arrive
function shouldn’t be responsible for doing the dispatching, but it probably should be responsible for saying “this event needs to be broadcast” – and something else will decide what to do with it… - Is it in fact the correct intent to let
handle_info
do things like this? In the past I’ve done something like this:
def send_heartbeat(_calling_pid) do
Registry.dispatch(Registry.Tick, :subject_to_time, fn entries ->
for {pid, _} <- entries, do: GenServer.cast(pid, :tick)
end)
end
I’m gonna keep handle_info
in mind just in case, but I thought the intent for that was basically for … Meta messages?