slouchpie

slouchpie

Associations, PubSub and live-updating - larger payload or enumerable iteration?

Imagine this familiar situation. We have a LiveView that renders a list of posts. Each post has an author (user) and multiple comments. Each comment also has an author (user). The LiveView process subscribes to some “new comment” topic. When a new comment is created on a post, this information is broadcast.

In this situation, it is clear that the PubSub payload should include the comment’s author preloaded. This could be a new user, who registered after the LiveView mounted. All is good.

Now imagine a different situation. We have a LiveView that renders a restaurant menu. A user can add items to their basket. A basket can be shared, so multiple users are using the same basket. The LiveView process subscribes to some “new basket item” topic. When an item is added to the basket, this information is broadcast. The LiveView is also subscribed to menu changes, e.g. menu item price changes. This means the LiveView process “knows” all the menu details.

In this situation, the basket item is associated to a menu item. My scruple is this: should the PubSub payload include the menu item preloaded on the created basket item struct? It seems wasteful, since, assuming our LiveView also subscribes to menu updates, the LiveView already “knows” the menu item details (not using streams here). Moreover, if, say, a menu item price changes, we will need update all assigned basket items that have this menu item preloaded.

With this in mind, it seems silly to trust/use a basket item’s preloaded menu item association. So I naturally think “OK, I will just find the menu item in the menu assign and infer details from that for rendering the basket item”. However, my menu items are a list, and iterating over a list for every basket item render is obviously very bad. OK, so maybe I should instead have a map of menu item IDs to menu items? Now the code feels very unwieldy, since I am perpetually transforming lists into maps, just for easy access of assoc details.

This entire train of thought has been a thorn in my side while doing LiveView development. I feel like no matter which approach I take, I am begetting obvious inefficiency.

Does anyone else feel this way? Does anyone have ancient secrets of efficient nested association assigns they want to share?

P.S. I love LiveView. It is awesome. I use it every day.

Most Liked

cmo

cmo

Obvious because you’ve measured it?

cmo

cmo

I merely intended to trigger the thought in you that maybe you should benchmark things instead of thinking you know what is and is not inefficient. I am sometimes surprised that my intuition about what will be faster is wrong when I benchmark different approaches.

Especially when you’re talking about a restaurant menu, which is not a large data structure.

slouchpie

slouchpie

Here is a pseudo-example

defmodule MyApp.Blurb do
  @moduledoc """
  BLURB = Brute Live Update of Rendered Basket
  """
  alias MyApp.Baskets.NebulexCache
  alias MyApp.Baskets.Basket

  @topic "blurb"
  def topic(basket_id), do: @topic <> basket_id
  def subscribe(basket_id), do: Phoenix.PubSub.subscribe(MyApp.PubSub, topic(basket_id))

  def broadcast(basket_id),
    do: Phoenix.PubSub.broadcast(MyApp.PubSub, topic(basket_id), {:blurb, basket_id})

  @doc """
  A simple way of updating a displayed basket in real-time.

  When a basket is updated in any kind of way, we broadcast just
  the basket ID and a message like `basket_updated`.

  Subscribers should then fetch the basket but ensure to do so using
  Nebucache or whatever we are using to cache function results.


  1. clear nebucache for a basket
  2. broadcast the basket ID and message
  """
  @spec clear_and_broadcast(Basket.id()) :: :ok
  def clear_and_broadcast(basket_id) do
    NebulexCache.clear_basket_id(basket_id)
    broadcast(basket_id)
  end
end

Then, if my basket changes in any kind of way at all (or even if something nested within basket, e.g. if someone changes the quantity of one of the items) then I just write a single line in the context function:

Blurb.clear_and_broadcast(basket_id)

I would love any feedback or criticism. I’m sure there are pitfalls with this approach that I am not seeing (such is life).

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New
WolfDan
After doing a port from a c++ library to my project in phoenix I’ve seen that I need a faster way to run this algorithm and I found this ...
New
mmmrrr
Just saw that dhh announced https://hotwire.dev/ Is it just me or is this essentially live view? :smiley: Although I like the “iFrame-e...
New
AstonJ
I’ve just started the Phoenix part of the utterly brilliant online course by @pragdave. On generating the Phoenix app he uses the --no-ec...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
AstonJ
If so I (and hopefully others!) might have some tips for you :slight_smile: But first, please say which area you’re finding most challen...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New
kostonstyle
Hi all How can I compare haskell with elixir, included tools, webservices, ect. Thanks
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement