mindreader
I am writing an application that uses pub sub between various processes quite heavily. I wrote it at first with the local Registry in elixir and it works great. But eventually I needed processes on a different nodes to subscribe to this data, so I had to look for an alternative.
I looked at gproc and syn and I was not too happy with them. gproc’s api is horrible and barely documented and I can’t even get it to work in global mode. It would be an extremely tough sell to my coworkers. Syn has all sorts of collision detection ability and requires all nodes be connected before it can be initialized, or god knows what happens, and all of that is overkill. All of my registries are on one node, and other nodes just pass a message to them once in awhile. Edit: And after reading it more in depth, I’m not sure process groups are what I’m looking for.
So I started writing my own. After I was about half done I realized I was writing elixir’s local Registry myself but worse, and the only real change that mattered was that I could pass in a name: {:global, :name}, into all of my versions of its functions. Registry makes every possible attempt to prevent you from doing that.
At this point I’m seriously considering copying elixir’s registry and just changing some functions to accept a global name tuple, and the only thing stopping me is that I’m wondering what trouble they were trying to prevent me from causing when they wrote this module in this fashion. So if someone could tell me why what I’m considering doing is a bad idea that’d be great.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 15 Posts
ryh
Just use gproc. If you don’t like the API, wrap the parts you don’t like in a better abstraction
Admittedly, my only experience with gproc is using this part:
https://github.com/uwiger/gproc/blob/master/doc/gproc.md#reg3
ryh
Ultimately, gproc is the answer. It has already solved the problem (and you will end up running into problems it has already solved). Take the functions you already created and use them as wrappers around the gproc calls.
michalmuskala
The simple (and boring) answer is that distributed registry is really, really hard to get right. The OTP team is already working on improving what’s available in Erlang itself, so there’s no need to duplicate efforts.
peerreynders
I realize that
gprochas richer features but I still don’t see the showstopper for using:global.register_name/2(with:global.whereis_name/1or{:global,term}) in the meantime - obviously I’m missing something.Azolo
Are you just using
Registrylike a pubsub system?If you’re using it for a PubSub then you are probably running a
:duplicateregistry, in which case there are better ways in handling Broadcasting across nodes than usingRegistry.dispatch.If you want to build it yourself and still use most of your
Registryimplementation then what you need to do is have aBroadcasterat each node that is part of a:pg2group or something. Then thisBroadcasteris actually in charge of dispatching messages.When it receives a local message it broadcasts the message to the other
Broadcasterprocesses in the:pg2group then runsRegistry.dispatch/3locally. When it receives a message from another node it just runsRegistry.dispatch/3locally.That’s basically what
phoenix_pubsubdoes. If you need something more than just PubSub thatRegistryprovided then I would still recommend a per nodeOrchestratorprocess of some kind.Once again though, this is for
:duplicateregistries. If you are using a:uniqueregistry then @michalmuskala comment about registration being hard becomes the plain fact of the matter.mindreader
I am using :duplicate, and I am using it for pub sub, but not every process gets the same data when an event fires. When they subscribe they send along an mfa, and then when an event occurs, the process takes its potentially large state and runs the mfa on it to summarize it into a smaller summary that goes to the subscriber. This is because the summary is different for each subscriber due to permissions or timezone of that particular user. Like if a user needs to get a count of calls that were presented to him since midnight in his timezone. Versus another user who needs any call at his company since midnight in some other timezone.
That means that I can’t just use a dumb
Broadcasterbecause I would have to send the entire state of each process to every node before it could be summarized, with no guarantee that any process even subscribed to that data.As for gproc, I’ve messed with it several times and I cannot get it to work. It seems to have what I need but when I try to use any global function I get the following error.
** (ErlangError) erlang error: :local_only
And I just don’t know what that means. If I could get past that I think I could maybe make this work.
peerreynders
This maybe?
[erlang-questions] How do I start gproc in a global way?
Azolo
I think maybe you’re using an
:latom where a:gatom should be used instead.But the way your constructing your system seems interesting. I probably would have done it the other way around, and have the map/reduce offloaded onto the subscribing processes.
Either way, if you can give me an example of the call your making that throws the error I may be able to tell you what’s going on.
josevalim
A very quick rundown of your options:
Registryis local onlygprochas a global mode but the consensus is that it is unreliable. so consider it local only.pg(part of OTP) if you need a distributed process group (duplicate keys)global(part of OTP) if you need a distributed process registry (unique keys)syn- you seem to already be aware of its pros/consPhoenix.Tracker, which is part of thephoenix_pubsubproject, as a distributed process group (duplicate keys)EDIT: Updated in 2023 to mention
pginstead ofpg2in Erlang/OTP.mindreader
This is probably why I was having a problem with gproc. I guess I’ll fool with it and see if I can’t get it working. If gproc defaults to local only mode that would certainly explain why it wouldn’t work.
For those that have used gproc, what happens when you need to add an additional node? Would it just know about that node the first time a process on the node tried to use it?