DEV Community

Cover image for Harness PubSub for Real-Time Features in Phoenix Framework
Rushikesh Pandit
Rushikesh Pandit

Posted on

Harness PubSub for Real-Time Features in Phoenix Framework

When it comes to building real-time web applications, the Phoenix framework is hard to beat. At the heart of its real-time capabilities lies Phoenix.PubSub, a powerful messaging system that allows processes to subscribe to and broadcast messages within an application. Whether you’re building live notifications, collaborative tools, or event-driven systems, PubSub is your go-to tool.

In this blog, we’ll explore how Phoenix.PubSub works, dive into practical use cases, and demonstrate step-by-step examples to integrate it into your projects.

What is Phoenix.PubSub?

Phoenix.PubSub is a publish-subscribe mechanism built into the Phoenix framework. It allows you to broadcast messages to multiple subscribers efficiently, enabling real-time communication across your application.

Key Concepts:

  • Publishers: Send messages to a specific topic.
  • Subscribers: Listen for messages on topics they are interested in.
  • Topics: Strings representing the channel for communication (e.g., "notifications", "room:lobby"). PubSub is transport-agnostic, meaning it can work seamlessly across distributed systems.

Why Use PubSub?

PubSub is an excellent fit for scenarios like:

  1. Real-time notifications: Push updates instantly to users (e.g., alerts, badges).
  2. Collaborative tools: Enable live edits or actions in shared environments (e.g., Google Docs-style collaboration).
  3. Event broadcasting: Notify multiple processes of significant events (e.g., user activity).
  4. Scalability: Distribute messages across nodes in a clustered environment.

Setting Up PubSub

PubSub is automatically included in new Phoenix applications, but to use it effectively, let’s break down the setup.

1. Configuration
Ensure your application’s PubSub module is defined in lib/my_app/application.ex. It’s typically added by default.

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Phoenix.PubSub, name: MyApp.PubSub}
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
Enter fullscreen mode Exit fullscreen mode

2. Broadcasting Messages

Use Phoenix.PubSub.broadcast/3 to send messages to a specific topic.

Phoenix.PubSub.broadcast(MyApp.PubSub, "notifications", %{message: "New user signed up!"})
Enter fullscreen mode Exit fullscreen mode

3. Subscribing to Topics

Processes can subscribe to a topic using Phoenix.PubSub.subscribe/2.

Phoenix.PubSub.subscribe(MyApp.PubSub, "notifications")
Enter fullscreen mode Exit fullscreen mode

Real-World Example: Notifications System

Let’s build a simple notification system where users receive real-time updates whenever a new notification is added.

Creating the PubSub Integration

1. Subscribe to Notifications
When a LiveView mounts, subscribe the process to the "notifications" topic.

def mount(_params, _session, socket) do
  Phoenix.PubSub.subscribe(MyApp.PubSub, "notifications")
  {:ok, assign(socket, notifications: [])}
end
Enter fullscreen mode Exit fullscreen mode

2. Handle Incoming Messages
When a message is broadcasted, handle it with handle_info/2 and update the LiveView state.

def handle_info(%{message: message}, socket) do
  {:noreply, assign(socket, notifications: [message | socket.assigns.notifications])}
end
Enter fullscreen mode Exit fullscreen mode

3. Broadcast Notifications
Trigger broadcasts from any part of the app (e.g., a controller or background worker).

def notify_users(message) do
  Phoenix.PubSub.broadcast(MyApp.PubSub, "notifications", %{message: message})
end
Enter fullscreen mode Exit fullscreen mode

LiveView Template

<div id="notifications">
  <h3>Notifications</h3>
  <ul>
    <%= for notification <- @notifications do %>
      <li><%= notification %></li>
    <% end %>
  </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

With these steps, users will receive live updates in their notifications list whenever notify_users/1 is called.

Advanced Use Case: Collaborative Editing

PubSub shines in collaborative tools. For instance, imagine a real-time collaborative text editor where multiple users edit the same document.

Broadcasting Edits

def handle_event("edit", %{"content" => content}, socket) do
  Phoenix.PubSub.broadcast(MyApp.PubSub, "document:123", %{content: content})
  {:noreply, socket}
end
Enter fullscreen mode Exit fullscreen mode

Subscribing to Edits

def mount(_params, _session, socket) do
  Phoenix.PubSub.subscribe(MyApp.PubSub, "document:123")
  {:ok, assign(socket, content: "")}
end

def handle_info(%{content: content}, socket) do
  {:noreply, assign(socket, content: content)}
end
Enter fullscreen mode Exit fullscreen mode

Testing PubSub

You can test your PubSub implementation easily using iex. Open multiple iex sessions and ensure they subscribe to the same topic:

Phoenix.PubSub.subscribe(MyApp.PubSub, "test_topic")

Phoenix.PubSub.broadcast(MyApp.PubSub, "test_topic", %{data: "Hello, PubSub!"})
Enter fullscreen mode Exit fullscreen mode

All subscribers to "test_topic" should receive the broadcast message.

Scaling PubSub Across Nodes

Phoenix.PubSub supports distributed systems out of the box. To enable clustering:

  1. Add :libcluster to your dependencies.
  2. Configure clustering in config/runtime.exs:
config :libcluster,
  topologies: [
    example: [
      strategy: Cluster.Strategy.Gossip
    ]
  ]
Enter fullscreen mode Exit fullscreen mode
  1. Start your application on multiple nodes, and messages will seamlessly propagate across them.

Phoenix.PubSub is a powerful tool for building real-time features in Elixir applications. Whether you’re creating a simple notification system or scaling to a distributed collaborative environment, PubSub provides the flexibility and performance you need.

If you’ve built something cool with Phoenix.PubSub, let me know in the comments—I’d love to hear about your experience!

Feel free to reach out if you need help.

LinkedIn: https://www.linkedin.com/in/rushikesh-pandit
GitHub: https://github.com/rushikeshpandit
Portfolio: https://www.rushikeshpandit.in

#myelixirstatus , #elixir , #phoenixframework

Top comments (0)