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:
- Real-time notifications: Push updates instantly to users (e.g., alerts, badges).
- Collaborative tools: Enable live edits or actions in shared environments (e.g., Google Docs-style collaboration).
- Event broadcasting: Notify multiple processes of significant events (e.g., user activity).
- 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
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!"})
3. Subscribing to Topics
Processes can subscribe to a topic using Phoenix.PubSub.subscribe/2
.
Phoenix.PubSub.subscribe(MyApp.PubSub, "notifications")
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
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
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
LiveView Template
<div id="notifications">
<h3>Notifications</h3>
<ul>
<%= for notification <- @notifications do %>
<li><%= notification %></li>
<% end %>
</ul>
</div>
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
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
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!"})
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:
- Add
:libcluster
to your dependencies. - Configure clustering in
config/runtime.exs
:
config :libcluster,
topologies: [
example: [
strategy: Cluster.Strategy.Gossip
]
]
- 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)