pejrich

pejrich

What's the best pattern for a pubsub event listener? GenServer seems like the wrong choice

Let’s say I have a basic slack-like chat app. User’s can post messages, like messages, reply to messages, etc. It’s build using LiveView, so when I message is created/liked I publish a event to pubsub so the live_view can handle the UI updates. That’s all fine and working, but let’s say there are side effects, like send the user a notifcation of the liked message, or updating the user’s point score for a liked message. Or emailing the user if a message is replied to. Etc.

One solution is something like this:

defmodule Notification.EventHandler do
   def start_link(), do: ...

  def init(_) do
    Phoenix.PubSub.subscribe(MyApp.PubSub, "notification_event")
    {:ok, nil}
  end

  def handle_info({:liked_message, msg}, state) do
    create_notification_here(msg)
    {:noreply, state}
  end
end

This seems ok, because at least it’s async to the user liking the message, but now all “notification_events” (let’s say those are :liked_message and :message_reply) are handled sequentially.

One way to slightly improve is to change the handle_info to:

  def handle_info({:liked_message, msg}, state) do
    Task.start(__MODULE__, :create_notification_here, [msg])
    {:noreply, state}
  end
  
  defp create_notification(msg), do: some_stuff_here()

Now at least the time it takes to create the notification is blocking the GenServer, but each event is still being handle sequentially.

Is there a better way to concurrently handle events like this?

Most Liked

al2o3cr

al2o3cr

This seems ok, because at least it’s async to the user liking the message, but now all “notification_events” (let’s say those are :liked_message and :message_reply) are handled sequentially.

This is a fact, but whether it’s a problem or not depends on your specific use case.

For instance, it provides a free guarantee that notifications are handled in precisely the order transmitted.

  def handle_info({:liked_message, msg}, state) do
    Task.start(__MODULE__, :create_notification_here, [msg])
    {:noreply, state}
  end

Be careful with patterns like this - if a LOT of messages come in at once, there’s no limit on how many processes this tries to start. Consider using something like :poolboy to get parallel workers with bounded resource consumption.

Where Next?

Popular in Questions Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54250 245
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

We're in Beta

About us Mission Statement