The Problem

Messages published to Redis channels don't reach subscribers. Applications relying on Pub/Sub for real-time notifications miss critical events. Subscribers appear connected but receive no messages, or messages arrive sporadically.

Understanding Redis Pub/Sub

Redis Pub/Sub features: - Publish/Subscribe pattern - One publisher, multiple subscribers - Channels - Named message destinations - Patterns - Subscribe to channel patterns (PSUBSCRIBE) - No persistence - Messages not stored, only delivered to active subscribers - Fire-and-forget - If no subscribers, message is dropped

Key commands: - PUBLISH channel message - Send message - SUBSCRIBE channel [channel...] - Subscribe to channels - PSUBSCRIBE pattern [pattern...] - Subscribe to patterns - PUBSUB CHANNELS - List active channels - PUBSUB NUMSUB channel - Count subscribers

Diagnosis Commands

Check Active Channels

bash
redis-cli PUBSUB CHANNELS

Output shows channels with active subscribers:

bash
notifications
alerts
events:user1

Check Subscriber Count

bash
redis-cli PUBSUB NUMSUB mychannel

Output:

bash
mychannel 5

Shows channel name and subscriber count.

Check Pattern Subscriptions

bash
redis-cli PUBSUB NUMPAT

Returns count of pattern subscriptions across all clients.

List Connected Clients

bash
redis-cli CLIENT LIST | grep -E 'sub=[1-9]|psub=[1-9]'

Shows clients with subscriptions. Key fields: - sub - Number of channel subscriptions - psub - Number of pattern subscriptions - flags - Includes P for pub/sub client

Test Message Delivery

```bash # Terminal 1: Subscribe redis-cli SUBSCRIBE testchannel

# Terminal 2: Publish redis-cli PUBLISH testchannel "hello"

# Terminal 1 should receive: # 1) "message" # 2) "testchannel" # 3) "hello" ```

Common Pub/Sub Issues

Issue 1: Subscriber Connected Too Late

Messages published before subscription are lost.

Problem:

```bash # Publisher sends message redis-cli PUBLISH alerts "system_down"

# Subscriber connects AFTER message sent redis-cli SUBSCRIBE alerts # Never receives "system_down" message ```

Solution:

Redis Pub/Sub is real-time only. Use Redis Streams for persistence:

```bash # Use streams for persisted messages redis-cli XADD alerts * message system_down

# Consumer reads missed messages redis-cli XREAD STREAMS alerts 0 ```

Issue 2: Wrong Channel Name

Channel names must match exactly.

Problem:

```bash # Publisher redis-cli PUBLISH user:123:notifications "new_message"

# Subscriber subscribes to wrong pattern redis-cli SUBSCRIBE user:notifications # Doesn't match - no message received ```

Solution:

Verify channel names:

```bash # Check active channels redis-cli PUBSUB CHANNELS "user:*"

# Subscribe to exact channel redis-cli SUBSCRIBE user:123:notifications

# Or use pattern subscription redis-cli PSUBSCRIBE user:*:notifications ```

Issue 3: Pattern Subscription Mismatch

Pattern subscriptions have different message format.

Problem:

```bash # Subscriber uses pattern redis-cli PSUBSCRIBE user:*

# Message format is different: # 1) "pmessage" <- Pattern message type # 2) "user:*" <- Pattern matched # 3) "user:123" <- Actual channel # 4) "hello" <- Message

# Application expecting 3-element format fails ```

Solution:

Handle both message formats:

```python import redis

r = redis.Redis()

pubsub = r.pubsub() pubsub.psubscribe('user:*')

for message in pubsub.listen(): if message['type'] == 'pmessage': pattern = message['pattern'] # user:* channel = message['channel'] # user:123 data = message['data'] # hello elif message['type'] == 'message': channel = message['channel'] data = message['data'] ```

Issue 4: Blocked Client Can't Issue Commands

Subscribed clients can only receive, not execute other commands.

Problem:

```bash redis-cli SUBSCRIBE mychannel # Now blocked - can't issue GET, SET, etc.

redis-cli GET somekey (error) ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context ```

Solution:

Use separate connections for pub/sub and commands:

```python import redis

# Connection for regular commands r = redis.Redis()

# Separate connection for pub/sub pubsub_client = redis.Redis() pubsub = pubsub_client.pubsub() pubsub.subscribe('mychannel')

# Can use r for commands while pubsub_client receives messages r.set('key', 'value')

for message in pubsub.listen(): if message['type'] == 'message': # Use r connection for database operations r.set('last_message', message['data']) ```

Issue 5: Client Disconnected Silently

Network issues drop pub/sub connections without notification.

Diagnosis:

bash
# Check if client still subscribed
redis-cli CLIENT LIST | grep -E 'sub=[1-9]'

Solution:

Implement health checks and reconnect:

```python import redis import time import threading

class ReliablePubSub: def __init__(self, host='localhost', port=6379): self.host = host self.port = port self.channels = [] self.patterns = [] self._stop = threading.Event()

def subscribe(self, *channels): self.channels.extend(channels)

def psubscribe(self, *patterns): self.patterns.extend(patterns)

def run(self, handler): while not self._stop.is_set(): try: client = redis.Redis(host=self.host, port=self.port) pubsub = client.pubsub()

if self.channels: pubsub.subscribe(*self.channels) if self.patterns: pubsub.psubscribe(*self.patterns)

# Health check thread def health_check(): while not self._stop.is_set(): try: client.ping() except redis.ConnectionError: break time.sleep(30)

health_thread = threading.Thread(target=health_check) health_thread.start()

for message in pubsub.listen(): if message['type'] in ('message', 'pmessage'): handler(message)

except redis.ConnectionError: print("Connection lost, reconnecting...") time.sleep(5)

def stop(self): self._stop.set() ```

Issue 6: High Message Volume Overwhelms Subscriber

Fast publishing exceeds subscriber processing capacity.

Diagnosis:

bash
# Check publish rate
redis-cli INFO stats | grep total_commands_processed

Solution:

  1. 1.Use batch processing:

```python import redis

r = redis.Redis() pubsub = r.pubsub() pubsub.subscribe('high_volume_channel')

# Process in batches batch = [] batch_size = 100

for message in pubsub.listen(): if message['type'] == 'message': batch.append(message['data'])

if len(batch) >= batch_size: process_batch(batch) batch = [] ```

  1. 1.Use Redis Streams instead:
bash
# Streams support consumer groups for parallel processing
redis-cli XADD events * data message_content

Issue 7: Buffer Overflow Disconnection

Pub/sub clients with high output buffers get disconnected.

Diagnosis:

```bash # Check client output buffer redis-cli CLIENT LIST | grep -E 'sub=[1-9]'

# Check pub/sub buffer limits redis-cli CONFIG GET client-output-buffer-limit | grep pubsub ```

Solution:

Increase buffer limits:

bash
redis-cli CONFIG SET client-output-buffer-limit "pubsub 256mb 64mb 60"

Or in redis.conf:

conf
client-output-buffer-limit pubsub 256mb 64mb 60

Testing Pub/Sub Reliability

Comprehensive Test

```bash #!/bin/bash # test_pubsub.sh

CHANNEL="test_channel_$(date +%s)"

# Start subscriber in background (redis-cli SUBSCRIBE $CHANNEL > /tmp/sub_output.txt &) & SUB_PID=$!

sleep 1

# Publish test message redis-cli PUBLISH $CHANNEL "test_message_1"

sleep 1

# Check subscriber received message if grep -q "test_message_1" /tmp/sub_output.txt; then echo "SUCCESS: Message received" else echo "FAIL: Message not received" fi

# Cleanup redis-cli CLIENT KILL SKIPME yes kill $SUB_PID 2>/dev/null rm /tmp/sub_output.txt ```

Pattern Test

```bash # Subscribe to pattern redis-cli PSUBSCRIBE "events:*" & SUB_PID=$!

sleep 1

# Publish to matching channel redis-cli PUBLISH "events:user1" "hello" redis-cli PUBLISH "events:system" "alert"

sleep 1

# Verify pattern matching works # Messages should appear with "pmessage" type ```

Monitoring Pub/Sub Health

Monitor Script

```bash #!/bin/bash # Monitor pub/sub metrics

while true; do CHANNELS=$(redis-cli PUBSUB CHANNELS | wc -l) NUMPAT=$(redis-cli PUBSUB NUMPAT) PUB_CLIENTS=$(redis-cli CLIENT LIST | grep -c 'flags=.*P')

echo "$(date): Channels=$CHANNELS Patterns=$NUMPAT PubClients=$PUB_CLIENTS"

# Check for clients with no subscriptions ORPHAN=$(redis-cli CLIENT LIST | grep 'flags=.*P' | grep -E 'sub=0' | grep -E 'psub=0') if [ -n "$ORPHAN" ]; then echo "WARNING: Pub/sub clients with no subscriptions" fi

sleep 60 done ```

Configuration Best Practices

```conf # redis.conf

# Pub/sub buffer limits client-output-buffer-limit pubsub 32mb 8mb 60

# TCP keepalive for connection health tcp-keepalive 300

# Client timeout (0 = no timeout for pub/sub) timeout 0 ```

Alternative: Redis Streams

For reliable message delivery, consider Redis Streams:

```bash # Streams provide persistence and consumer groups redis-cli XADD notifications * message content

# Multiple consumers can process reliably redis-cli XGROUP CREATE notifications mygroup 0 MKSTREAM redis-cli XREADGROUP GROUP mygroup consumer1 STREAMS notifications > redis-cli XACK notifications mygroup <message_id> ```

Benefits: - Messages persist until explicitly deleted - Consumer groups support multiple workers - Can recover missed messages - Track processing state

Verification

After fixing issues:

```bash # Test basic pub/sub redis-cli SUBSCRIBE verification_test & sleep 1 redis-cli PUBLISH verification_test "verify" sleep 1

# Check subscriber count redis-cli PUBSUB NUMSUB verification_test # Should show 1 subscriber

# Cleanup redis-cli UNSUBSCRIBE verification_test ```