Pub/Sub for Real-Time Events Between Services
AI generated
SET
TTL
Redis · Pub/Sub · Real-Time Communication
Pub/Sub for Real-Time Events Between Services
Fire-and-forget without queue overhead

Redis Pub/Sub distributes messages in real time to all currently connected subscribers, without storing them or giving any delivery guarantee. This fire-and-forget semantic makes Pub/Sub ideal for live notifications between services, but unsuitable for anything that needs persistence or guaranteed delivery.

16 min read PUBLISH · SUBSCRIBE · PSUBSCRIBE · Fire-and-Forget Redis 7.x · Predis · phpredis

1. What Redis Pub/Sub fundamentally does

Redis Pub/Sub implements the classic publish-subscribe pattern: a publisher sends a message to a named channel, and every client that subscribed to that channel at the time of sending receives the message immediately. Unlike lists or streams, Redis does not store the message. It exists only for the fraction of a second it takes to travel from the publisher to the currently connected subscribers, after which it is irretrievably gone.

This radical simplicity is both the greatest strength and the greatest limitation of Pub/Sub. There is no queue, no acknowledgment, no retry logic. A subscriber that is not connected at the moment of publishing misses the message permanently. This property makes Pub/Sub the ideal tool for genuine real-time events where only the current state matters, but the worst possible choice for anything that requires reliable delivery.

2. PUBLISH and SUBSCRIBE in detail

The basic pattern of Redis Pub/Sub consists of two commands. SUBSCRIBE channel registers a client as a subscriber to a specific channel and then blocks the connection to receive incoming messages. PUBLISH channel message sends a message to all currently connected subscribers of that channel and returns the number of recipients, a useful indicator of whether anyone was listening at all.

It is important that a Redis connection in subscribe mode is blocked for almost all other commands. A client that has called SUBSCRIBE can no longer execute GET or SET operations on the same connection until it unsubscribes with UNSUBSCRIBE. In practice this means that applications using both regular Redis operations and Pub/Sub need two separate connections for that.


# Terminal 1: subscribe to a channel and block waiting for messages
redis-cli SUBSCRIBE orders:updates
# Reading messages... (press Ctrl-C to quit)
# 1) "subscribe"
# 2) "orders:updates"
# 3) (integer) 1

# Terminal 2: publish a message
redis-cli PUBLISH orders:updates '{"orderId":8842,"status":"shipped"}'
# (integer) 1   -- one subscriber received the message

# Terminal 1 immediately shows:
# 1) "message"
# 2) "orders:updates"
# 3) "{\"orderId\":8842,\"status\":\"shipped\"}"

3. PSUBSCRIBE: pattern based subscriptions

Besides the exact channel name, Redis also supports pattern based subscriptions through glob style wildcards using PSUBSCRIBE pattern. A subscription to orders:* receives messages from every channel starting with orders:, such as orders:updates, orders:cancelled or orders:8842:status. This is especially useful when channel names are dynamically composed from IDs, for example per user or per order, and a central service needs to observe all events regardless of the specific ID.

The price of this flexibility is performance: pattern matching is more computationally expensive than the exact match used by SUBSCRIBE, because Redis has to check all registered patterns against the published channel name on every PUBLISH operation, not just perform a hash lookup. With a very high number of active pattern subscriptions, this overhead can become noticeable, which is why PSUBSCRIBE should be used deliberately rather than as the default solution for every use case.


# Subscribe to all order related channels at once
redis-cli PSUBSCRIBE "orders:*"
# 1) "psubscribe"
# 2) "orders:*"
# 3) (integer) 1

# Publish on a specific channel
redis-cli PUBLISH orders:8842:status '{"status":"delivered"}'

# The received message additionally shows the matched pattern:
# 1) "pmessage"
# 2) "orders:*"
# 3) "orders:8842:status"
# 4) "{\"status\":\"delivered\"}"

4. Implementing Pub/Sub in PHP with Predis

In PHP, Predis uses a dedicated, blocking API for Pub/Sub that differs from the usual request-response pattern of Redis commands. The subscriber client opens a persistent connection and calls a callback for every incoming message, which typically runs in a long lived worker process rather than a classic short lived web request.

The publisher, on the other hand, is a normal, short lived call that can easily be made from a controller or service within a web request, since PUBLISH does not block and returns immediately.


<?php

declare(strict_types=1);

// Publisher: fires an event when an order status changes
final class OrderEventPublisher
{
    public function __construct(private readonly \Predis\Client $redis)
    {
    }

    /**
     * Publish an order status change as a real-time event.
     */
    public function publishStatusChange(int $orderId, string $status): void
    {
        $payload = json_encode(['orderId' => $orderId, 'status' => $status]);
        $this->redis->publish('orders:updates', $payload);
    }
}

// Subscriber: long-running worker process
final class OrderEventSubscriber
{
    public function __construct(private readonly \Predis\Client $redis)
    {
    }

    /**
     * Block and react to incoming order update events.
     */
    public function listen(): void
    {
        $pubsub = $this->redis->pubSubLoop();
        $pubsub->subscribe('orders:updates');

        foreach ($pubsub as $message) {
            if ($message->kind === 'message') {
                $event = json_decode($message->payload, true);
                echo "Order {$event['orderId']} changed to {$event['status']}\n";
                // Forward to WebSocket clients, trigger notifications, etc.
            }
        }
    }
}

5. Understanding fire-and-forget semantics

The term fire-and-forget describes exactly what PUBLISH does: the message is sent, and the publisher does not care whether or how it arrives. There is no confirmation from an individual recipient, only the total count of channels the message was delivered to. This number says nothing about whether the message was actually processed, only that it reached the network layer of the subscriber connection.

In practice, fire-and-forget means: if a subscriber process crashes while processing, the message is lost without any other part of the system ever finding out. There is no automatic retry mechanism, no dead letter queue, no way to retrieve missed messages later. Applications relying on this semantic must deliberately accept that occasional message loss is a normal, expected operating condition, not an exception.

6. Practical use cases for real-time events

Redis Pub/Sub is excellent for use cases where only the most current state matters and a missed event is superseded anyway by the next state update. Live chat systems are a classic example: if a message is lost because a client was briefly disconnected, the next connection typically shows the current chat history from a separate, persistent data source, Pub/Sub only delivers the real-time supplement for clients that are already connected.

Other proven use cases include live dashboards with constantly refreshing metrics, presence indicators such as "user X is currently online", cache invalidation across multiple application instances where a central publisher informs every instance about changed keys, and multiplayer game state where every missed frame is replaced by the next one anyway. The shared characteristic of all these cases: the value of a single message decays almost instantly.


# Cache invalidation across multiple application instances via Pub/Sub
redis-cli SUBSCRIBE cache:invalidate

# Central publisher informs every instance about a changed key
redis-cli PUBLISH cache:invalidate "product:4711"

# Each instance then clears its local in-process cache for that key

7. Limits: no persistence, no replay

The central limitation of Redis Pub/Sub is the complete absence of persistence. Unlike Redis Streams or a classic message queue, there is no way to retrieve past messages, no matter how briefly the client was offline. A restart of a subscriber process, even one lasting only a few milliseconds, means the irretrievable loss of every message published during that time.

This limit makes Pub/Sub unsuitable for anything that relies on completeness: financial transactions, order confirmations, audit logs, or any kind of event whose loss leads to an inconsistent system state. For such cases, Redis Streams with their consumer group logic and persistent message IDs are the right choice, or a dedicated message queue like RabbitMQ, built specifically for this problem.

8. Pub/Sub in clustered Redis environments

In a Redis Cluster, a message is by default propagated to every node in the cluster, so that subscribers receive all messages regardless of which node they are connected to. This behavior works reliably but generates additional network traffic between nodes, which can become a bottleneck at very high message frequency. Since Redis 7, a so called sharded Pub/Sub variant exists via SSUBSCRIBE and SPUBLISH, where messages are only distributed within the shard responsible for the given channel's hash slot.

Sharded Pub/Sub significantly reduces cluster wide broadcast overhead and is the recommended choice for cluster deployments with high event frequency. The difference for the application is minimal: instead of SUBSCRIBE and PUBLISH, only SSUBSCRIBE and SPUBLISH are used, behavior for the individual client stays identical, only the internal distribution within the cluster changes.


# Sharded Pub/Sub since Redis 7: reduces cluster broadcast
redis-cli SSUBSCRIBE orders:updates
redis-cli SPUBLISH orders:updates '{"orderId":8842,"status":"shipped"}'

# Check the number of active Pub/Sub channels
redis-cli PUBSUB CHANNELS "orders:*"

# Determine the number of subscribers per channel
redis-cli PUBSUB NUMSUB orders:updates

9. Pub/Sub compared to streams and queues

The choice between Pub/Sub, streams and dedicated message queues depends entirely on whether persistence and guaranteed delivery are needed or whether pure real-time distribution is enough.

Property Pub/Sub Redis Streams
Persistence None, message decays immediately Yes, messages remain in the stream
Replay Not possible Yes, via message ID
Delivery guarantee None, only connected clients Yes, with consumer groups and ACK
Latency Minimal, direct delivery Very low, slightly higher than Pub/Sub
Typical use Live dashboards, presence, chat supplement Event sourcing, task queues with history

Anyone who needs guaranteed delivery, replay capability or message history should switch to Redis Streams or a dedicated message queue. Pub/Sub remains the right choice when only the current moment matters and implementation effort should stay minimal.

Mironsoft

Redis architecture, real-time communication and microservices

Need real-time events built between your services?

We design event architectures with Redis Pub/Sub or Streams, depending on your persistence and delivery guarantee needs, and integrate them cleanly into your existing service landscape.

Architecture Design

Choosing Pub/Sub, Streams or a message queue to fit the use case

Implementation

Building robust publisher and subscriber workers in PHP and other languages

Scaling

Sharded Pub/Sub and cluster configuration for high event frequency

10. Summary

Redis Pub/Sub with PUBLISH, SUBSCRIBE and PSUBSCRIBE delivers real-time events to all currently connected subscribers, without storing messages or giving any delivery guarantee. This fire-and-forget semantic is ideal for live dashboards, presence indicators, chat supplements and cache invalidation across multiple instances, where the value of a single message decays almost instantly and losing it is uncritical.

For anything that needs persistence, replay or guaranteed delivery, Pub/Sub is the wrong choice, here Redis Streams with consumer groups or a dedicated message queue are the right answer. Since Redis 7, sharded Pub/Sub via SSUBSCRIBE and SPUBLISH additionally reduces cluster wide broadcast overhead at high event frequency.

Pub/Sub for real-time events, the essentials at a glance

Basic Pattern

PUBLISH sends, SUBSCRIBE receives exact channels, PSUBSCRIBE allows pattern based subscriptions.

Fire-and-Forget

No acknowledgment, no queue. Missed messages are irretrievably lost.

Ideal Use Cases

Live dashboards, presence indicators, cache invalidation, multiplayer state.

Limits

No persistence, no replay. Use Streams or a message queue for guaranteed delivery.

11. FAQ: Pub/Sub for Real-Time Events

1Are messages stored?
No, only currently connected subscribers receive the message, then it is irretrievably gone.
2SUBSCRIBE vs. PSUBSCRIBE?
SUBSCRIBE is exact, PSUBSCRIBE allows wildcards like orders:*, but is more expensive.
3SUBSCRIBE and GET together?
No, a connection in subscribe mode needs a separate connection for normal commands.
4What does fire-and-forget mean?
No acknowledgment, no retry, no dead letter queue when a message is lost.
5Best use cases?
Live dashboards, presence indicators, cache invalidation, supplements to persistent systems.
6Suitable for critical events?
No, a connection drop means irretrievable loss. Use streams or a message queue instead.
7What is sharded Pub/Sub?
SSUBSCRIBE and SPUBLISH since Redis 7, reduces cluster wide broadcast overhead.
8Check subscriber count?
With PUBSUB NUMSUB channelname, or via the return value of PUBLISH.
9Subscriber in a web request?
Usually not, the subscriber runs in a long lived worker process.
10Combine with WebSockets?
Yes, a very common pattern for real-time updates to browser clients.