Welcome back! In this lesson, we will dive into another powerful feature of Redis: Publish/Subscribe (Pub/Sub) messaging. This topic builds on our understanding of Redis and introduces a dynamic way to enable real-time communication within your applications.
In this lesson, you will learn how to set up and use Redis Pub/Sub messaging to send and receive messages using C++ and Boost.Redis. We'll create a single program that demonstrates both subscribing to and publishing messages on a channel.
Important notes:
- Dedicated connection for subscribers: The subscriber uses a separate Redis connection that operates in subscription mode.
- Asynchronous event-driven model: We use Boost.Asio's
io_contextto handle asynchronous operations. - RESP3 push messages: Redis sends Pub/Sub messages as push events that we receive through
async_receive. - Two connections: One for subscribing (enters special subscriber mode) and one for regular commands like PUBLISH.
Let's start by setting up our includes and creating two Redis connections:
What's happening here:
- We create an
io_context, which is the event loop that drives all asynchronous operations. - We create two separate connections:
sub_connfor subscribing andpub_connfor publishing. - Why two connections? Once a connection enters subscriber mode (after SUBSCRIBE), it can only receive push messages and cannot execute regular commands. That's why we need a separate connection for PUBLISH.
- Both connections are started with
async_run(), which establishes the connection asynchronously.
Before moving on, it helps to visualize why this example uses two Redis connections instead of one:

This diagram highlights the key Pub/Sub design in our program:
sub_connis dedicated to subscribing and receiving Pub/Sub messages.pub_connis used for regular Redis commands such asPUBLISH.- Redis sends subscribed messages back to
sub_connas RESP3 push messages. - We use two connections because the subscribed connection is dedicated to Pub/Sub message handling.
With that architecture in mind, let's build the receive loop that listens for incoming Pub/Sub messages.
Before subscribing, we need to set up a loop that continuously listens for incoming messages:
Breaking it down:
generic_responsecan parse any Redis response, including push messages.set_receive_response()tells the connection where to store the next incoming message.async_receive()waits asynchronously for Redis to push a message to us.- When a message arrives, we parse the RESP3 format:
nodes[1].value: The message type ("message", "subscribe", "unsubscribe", etc.)nodes[2].value: The channel name
Now we can subscribe to the "notifications" channel. Add this to your main() function:
Key points:
- We call
start_receive_loop()before subscribing to ensure we don't miss any messages. - We use
request::push()to build the SUBSCRIBE command with the channel name "notifications". - The response uses
boost::redis::ignore_tbecause we don't need to process the subscription confirmation here—it arrives as a push message handled by our receive loop. async_exec()sends the command asynchronously.
Now let's publish a message after a short delay to ensure the subscription is active:
What's happening:
- We use
steady_timerto wait 1 second before publishing. This ensures the subscription is fully active. - We create a PUBLISH command with the channel name "notifications" and payload "Hello, Redis!".
- The response type is
intbecause PUBLISH returns the number of subscribers who received the message. - We use
std::get<0>(*pub_resp).value()to extract the integer count from the response. - After publishing, we cancel the publisher connection since we're done.
ioc.run()blocks and processes all asynchronous events until all work is complete.
Compilation:
Execution:
Example output:
Let's recap the important Pub/Sub concepts:
-
Dedicated subscriber connection: Once you subscribe, that connection enters a special mode and can only receive push messages. That's why we use two separate connections.
-
RESP3 push messages: Redis uses RESP3 protocol to push messages to subscribers. The format is:
["message", "<channel>", "<payload>"]. We parse this usinggeneric_response. -
Asynchronous receive loop: We continuously call
async_receive()to listen for push messages. Each message triggers our callback, which processes it and callsasync_receive()again to keep listening. -
Channel-based routing: Publishers send messages to channels (like "notifications"). All subscribers listening to that channel receive the message.
-
Delivery count: PUBLISH returns the number of current subscribers who received the message, but it doesn't guarantee delivery if a subscriber disconnects.
The Pub/Sub messaging model is essential for enabling real-time communication in modern applications. Whether it's sending notifications to users, building chat systems, or updating dashboards live, Pub/Sub makes these patterns straightforward.
Here's why mastering Pub/Sub in Redis is important:
- Real-Time Communication: Update parts of your application as events occur for a seamless user experience.
- Decoupled Architecture: Publishers and subscribers are independent, making systems more modular and maintainable.
- Scalability: Add more subscribers or publishers without restructuring core logic.
- Event-Driven Design: Build responsive systems that react to events as they happen.
With Pub/Sub and Boost.Redis's asynchronous API, you can build responsive, scalable, and maintainable real-time features. The asynchronous model allows your applications to handle many concurrent operations efficiently without blocking threads.
