nidu
What's the idiomatic way to broadcast messages related to context updates
Hello, I have a code organization question.
Let’s say I have a Blog app with posts.ex context which is responsible for managing posts. When a new post is added - I’d like to send a pubsub message about it using BlogWeb.Endpoint.broadcast.
What would be the right way to do it? The simplest one to me is to broadcast inside Blog.create_post, but it feels that Blog shouldn’t depend on BlogWeb. Other options I see are:
- Add another
posts.excontext insideBlogWeb, that will either wrap methods likecreate_post(or for claritycreate_post_and_broadcastand add broadcast there. This feels not to so bad, but caller has to know that for some operations he has to go toBlogWeb.Postsinstead ofBlog.Posts. - Or again create this new
posts.exand just provide broadcast methods there, then caller must call broadcast aftercreate_post, which sounds error prone.
Could you please tell if there’s a clear idiomatic way of doing it or share a good example? Thanks!
Marked As Solved
drl123
What version of Phoenix are you running? Phoenix 1.6 starts the pubsub server under the app (Blog, not BlogWeb). Previous versions (don’t remember how far back) started it under the Endpoint.
So if you are using Phoenix Channels, when your channel connects, it should subscribe to changes on the models/contexts it is concerned about. Your context then broadcasts on the app pubsub (Blog.Pubsub) and the channel then maps that application pubsub to it’s channel client(s). It’s basically the same if you are using LiveView, just the LV does the subscription instead of the channel.
Chris McCord’s video intro to LiveView on the Phoenix home page explains the basic concept (it’s about mid-way through). https://youtu.be/MZvmYaFkNJI
So it’s kind of flipping what you said on its head. The client (web-side) should subscribe to the app’s pubsub topic it cares about (i.e. posts). The client manages what to do with the info it receives from the app. The app-side is only concerned about publishing on the app’s pubsub. That subscriber could be a web client, or it could be another piece of the app, or even another application that shares the cluster. So the publisher is blissfully unaware of which clients are subscribing to it and receiving the broadcasts, and even what they are going to do with that information.
The app never reaches OUT from its domain. It only broadcasts on its internal pubsub. The client-side reaches INTO the domain from the outside, just as it does when interacting with context actions, and decides what it wants notified of.
Hope that rather long-winded explanation was helpful ![]()
Also Liked
drl123
Guys, take a step back here and look at how Phoenix.PubSub is used by Phoenix. It basically is configured to be the ‘Notifier’ for the Phoenix application. When you configure the Phoenix Endpoint, you specify the pubsub (aka Notifier) to be used as MyApp.Pubsub…just as you were proposing to do with MyApp.Notifier.Phx, BUT from the other side. Now the Web side depends upon the Core and the Core is not dependent upon and unaware of the Web.
IMHO that you might be better off to just have your core application explicitly list a dependency on the phoenix_pubsub library in mix.exs, rather than have it injected by the Phoenix (Web Framework). You don’t need all of Phoenix here if you aren’t going to use it…just the pubsub library which is a standalone Hex package. Then that phoenix_pubsub library is akin to your Notifier module, but you have a one-way dependency (Web depends upon Core, Core does NOT depend upon Web).
Think of it this way: What if you wanted to use your core app with a ‘client’ other than Phoenix? Your Core would still have references to MyAppWeb.Endpoint in your proposal. Following Chris McCord’s, it would not.
The original post asked what the most idiomatic way to broadcast messages was and I would tend to trust the framework author’s methodology here! ![]()
PS…bonus points: it’s a whole lot easier to grok for someone new to your code when there isn’t that extra layer (that still has you coupled in the wrong direction)!
RudManusachi
The simplest one to me is to broadcast inside
Blog.create_post, but it feels thatBlogshouldn’t depend onBlogWeb
I agree.
I would think: If there is only 1 place where I want to broadcast after create then, just broadcast it from there after create =)
If I find that there are multiple different places where I want to do that, then it feels like there is a need for such create_post_and_broadcast ![]()
nidu
Thanks! I’m going to follow the way it’s done in the video (that’s a very good source) - use Phoenix.PubSub instead of BlogWeb.Endpoint. I guess I’ve been using Endpoint here not for it’s intended purpose.
Popular in Questions
Other popular 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
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









