Series MapLesson 20 / 57
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Build CoreOrdered learning track

Redis Pub/Sub

Redis Pub/Sub mental model, publish/subscribe lifecycle, fire-and-forget delivery, no durability, no replay, subscriber offline behavior, message loss, cache invalidation use case, and comparison with Streams, Kafka, and RabbitMQ.

13 min read2428 words
PrevNext
Lesson 2057 lesson track11–31 Build Core
#redis#pubsub#notification#message-loss+4 more

Part 020 — Redis Pub/Sub

Redis Pub/Sub is a lightweight notification mechanism.

It lets one client publish a message to a channel, and other currently connected clients subscribed to that channel receive it.

The most important production rule is simple:

Redis Pub/Sub is not durable messaging.

It has:

  • no persistence
  • no replay
  • no consumer groups
  • no acknowledgments
  • no broker-side retry
  • no offline subscriber catch-up

That makes it useful for live notifications and lightweight coordination signals.

It makes it risky for business-critical events.


1. Core Mental Model

Redis Pub/Sub is like an in-memory broadcast pipe.

publisher -> Redis channel -> currently connected subscribers

If a subscriber is connected and subscribed, it receives the message.

If it is offline, disconnected, restarting, lagging, or not yet subscribed, it misses the message.

There is no stored backlog.


2. Why Pub/Sub Exists

Pub/Sub exists for low-latency message fan-out where losing a message is acceptable or recoverable.

Examples:

  • cache invalidation hints
  • local cache clear signals
  • dashboard refresh notifications
  • lightweight cluster node notifications
  • configuration refresh hints
  • non-critical UI/backend notifications
  • internal ephemeral coordination

It should not be used for:

  • order creation events
  • payment events
  • quote submission events
  • audit events
  • compliance events
  • durable integration events
  • workflow state transitions
  • job queues requiring retry
  • messages requiring replay

For those, use Kafka, RabbitMQ, Redis Streams, a database-backed outbox, or a dedicated workflow engine depending on the requirement.


3. Basic Commands

3.1 PUBLISH

Publish a message to a channel:

PUBLISH cache:invalidation:quote '{"tenantId":"T-123","quoteId":"Q-456","version":12}'

Redis returns the number of clients that received the message at that moment.

Important: that count is not a durability guarantee.


3.2 SUBSCRIBE

Subscribe to one or more channels:

SUBSCRIBE cache:invalidation:quote

The connection enters subscriber mode and receives messages.

In Java clients, Pub/Sub usually requires a dedicated connection or listener abstraction.


3.3 PSUBSCRIBE

Pattern subscription:

PSUBSCRIBE cache:invalidation:*

This receives messages from channels matching the pattern.

Pattern subscriptions are convenient, but broad patterns can increase message processing noise and operational ambiguity.


3.4 UNSUBSCRIBE

Unsubscribe from channels:

UNSUBSCRIBE cache:invalidation:quote

Useful during shutdown or listener lifecycle management.


4. Message Lifecycle

Pub/Sub lifecycle:

flowchart TD A[Publisher Java service] --> B[PUBLISH channel message] B --> C[Redis Pub/Sub subsystem] C --> D{Subscriber connected now?} D -->|Yes| E[Message delivered to subscriber connection] D -->|No| F[Message is lost] E --> G[Subscriber callback handles message] G --> H[Local cache invalidated or action triggered]

There is no pending state.

There is no retry state.

There is no acknowledgement state.

This is the key difference from Redis Streams, Kafka, and RabbitMQ.


5. Pub/Sub in Java/JAX-RS Systems

In a Java/JAX-RS service, Pub/Sub usually appears in two roles:

  1. Publisher path from request/write operation.
  2. Subscriber background listener for cache invalidation or runtime signal.

Example flow:

PUT /quotes/{id}
  -> update PostgreSQL
  -> commit transaction
  -> delete Redis distributed cache key
  -> publish invalidation signal
  -> other service instances clear local cache

The Pub/Sub message is a hint to other instances.

It should not be the only correctness mechanism.

A safe design still needs:

  • TTL
  • versioned cache entries
  • fallback reload
  • local cache max age
  • observable invalidation lag
  • rebuild path

6. Pub/Sub and Local Cache Invalidation

A common enterprise use case is local + distributed cache coordination.

L1 cache: in-memory cache inside Java pod
L2 cache: Redis distributed cache
Source of truth: PostgreSQL

When one pod updates data:

1. Update PostgreSQL
2. Delete/update Redis cache
3. Publish invalidation event
4. Other pods evict their local L1 cache

This is useful because local caches do not see Redis key changes automatically.

But Pub/Sub message loss means local caches must not live forever.

Use:

  • local cache TTL
  • version check
  • max stale time
  • periodic refresh
  • safe fallback reload

7. Pub/Sub Is Fire-and-Forget

When a publisher sends a message, Redis does not persist the message.

Message exists only at delivery time.

If subscriber is offline:

message lost

If subscriber restarts:

message lost during restart window

If network hiccups:

message may be lost

If subscriber callback fails:

Redis does not retry

This is acceptable only when the system has another path to recover correctness.


8. Subscriber Offline Scenario

Consider this sequence:

T1: Pod B subscribes to cache:invalidation:quote
T2: Pod B restarts
T3: Pod A publishes invalidation for quote Q-456
T4: Pod B comes back online

Pod B missed the invalidation.

If Pod B has local cache entry Q-456 with no TTL, it may serve stale data indefinitely.

That is a design bug.

Safer local cache design:

Local cache entry has short TTL.
Cache value has version.
Read path can validate/reload.
Distributed Redis cache has TTL.
PostgreSQL remains source of truth.

9. Message Loss Scenario

Message loss can happen because of:

  • subscriber disconnect
  • subscriber restart
  • Redis failover
  • network partition
  • slow subscriber callback
  • client connection reset
  • application deployment
  • autoscaling
  • node drain

Therefore Pub/Sub cannot be used as the sole mechanism for:

  • financial correctness
  • order state transition
  • quote lifecycle transition
  • entitlement update correctness
  • regulatory audit trail
  • durable integration workflow

Use it as a signal, not a record.


10. Pub/Sub vs Redis Streams

DimensionRedis Pub/SubRedis Streams
DeliveryLive onlyStored entries
ReplayNoYes, within retention
Consumer groupNoYes
AckNoYes
Pending listNoYes
Retry patternApp-onlySupported through pending/claim patterns
Offline catch-upNoYes, if entries retained
Good forNotificationsLightweight durable queue/event stream

Use Pub/Sub when message loss is acceptable.

Use Streams when consumers need replay, pending tracking, ack, or retry.


11. Pub/Sub vs Kafka

Kafka is a durable distributed log.

Redis Pub/Sub is an ephemeral live broadcast.

Kafka is better for:

  • business events
  • integration events
  • replayable event history
  • event-driven architecture
  • consumer group scaling
  • audit-like event retention
  • cross-service durable event flow

Redis Pub/Sub is better for:

  • low-latency hints
  • local cache invalidation signal
  • temporary notifications
  • simple fan-out inside bounded infrastructure

Do not replace Kafka with Redis Pub/Sub for durable domain events.


12. Pub/Sub vs RabbitMQ

RabbitMQ is a message broker with queues, routing, acknowledgments, dead-lettering, and retry patterns.

Redis Pub/Sub does not provide those broker semantics.

RabbitMQ is better for:

  • work queues
  • retryable commands
  • consumer acknowledgments
  • DLQ routing
  • backpressure-aware processing
  • task distribution

Redis Pub/Sub is better for:

  • broadcast hints
  • non-critical event notifications
  • simple invalidation signals

Do not use Pub/Sub where RabbitMQ queue semantics are required.


13. Pub/Sub Channel Design

Channel names should be treated like API contracts.

Good channel name:

cache:invalidation:quote:v1

Better with environment/service scoping when needed:

prod:quote-service:cache:invalidation:quote:v1

But avoid putting PII in channel names.

Bad:

cache:invalidation:quote:john.doe@example.com

Channel naming should define:

  • environment
  • service/domain
  • event category
  • entity type
  • version
  • tenant scoping if required

14. Message Payload Design

A Pub/Sub message should be small, explicit, and versioned.

Example:

{
  "type": "QUOTE_CACHE_INVALIDATED",
  "version": 1,
  "tenantId": "T-123",
  "quoteId": "Q-456",
  "entityVersion": 12,
  "occurredAt": "2026-07-11T10:15:30Z",
  "sourceService": "quote-service",
  "correlationId": "req-abc-123"
}

Avoid large payloads.

Avoid embedding full business objects unless absolutely necessary.

For invalidation, usually send identity + version, not full state.


15. Versioning and Compatibility

Pub/Sub consumers may be on different versions during rolling deployment.

Therefore messages should be:

  • versioned
  • backward compatible
  • tolerant of unknown fields
  • explicit about type
  • small and stable

Java payload handling should avoid brittle deserialization.

Bad:

Deserialize directly into a class that changes frequently.

Better:

Use stable DTOs or tolerant JSON parsing with version handling.

16. Subscriber Implementation Concerns

A subscriber should not execute heavy work directly on the Pub/Sub callback thread/event loop.

Bad:

onMessage -> call PostgreSQL -> call remote service -> update large cache -> block listener

Better:

onMessage -> validate -> enqueue lightweight internal task -> return quickly

Risks of heavy callbacks:

  • subscriber falls behind
  • client timeout
  • event loop pressure
  • missed reconnect handling
  • delayed processing
  • message loss during instability

17. Java Client Connection Model

Redis Pub/Sub often needs a dedicated connection.

Reason:

A subscribed connection is in subscriber mode and cannot be used like a normal command connection.

Verify client behavior for:

  • Jedis
  • Lettuce
  • Redisson
  • connection pooling
  • reconnect behavior
  • listener threading
  • callback execution model
  • shutdown lifecycle

Do not accidentally consume normal Redis command pool connections for long-lived subscription listeners.


18. Error Handling

Subscriber errors should be contained.

A bad message should not kill the listener permanently.

Recommended behavior:

  • log message type/channel/correlation ID
  • increment failure metric
  • reject malformed payload safely
  • avoid infinite retry loop inside callback
  • continue listening after handler failure
  • expose listener health

For critical events, Pub/Sub is the wrong transport.

Do not compensate for non-durable transport by writing extremely complicated retry logic around Pub/Sub.

Use a durable broker instead.


19. Pub/Sub During Redis Failover

During Redis failover or reconnect:

  • subscriptions may drop temporarily
  • messages may be lost
  • Java client may resubscribe after reconnect
  • publisher may fail or publish to old primary depending on topology/client state
  • subscriber may miss invalidation events

This reinforces the design rule:

Pub/Sub must not be the only correctness path.

For cache invalidation, combine Pub/Sub with TTL and versioning.

For business events, use Kafka/RabbitMQ/Streams.


20. Pub/Sub in Redis Cluster

Redis Cluster adds operational considerations.

Pub/Sub behavior depends on Redis version and client support.

Review carefully:

  • which node receives subscriptions
  • whether sharded Pub/Sub is used
  • how client handles cluster topology changes
  • whether messages are broadcast across cluster as expected
  • whether managed service supports required Pub/Sub behavior

Do not assume standalone Redis Pub/Sub behavior automatically maps to cluster topology.

Internal verification is required.


21. Kubernetes Deployment Concerns

Kubernetes makes Pub/Sub loss scenarios more common:

  • rolling updates restart subscribers
  • HPA scales pods up/down
  • node drains disconnect listeners
  • readiness probes may pass before subscription is active
  • network policy changes may break subscriptions
  • DNS or service endpoint changes may trigger reconnect

A subscriber pod should expose health that answers:

Is the listener connected and subscribed?

Not merely:

Is the HTTP server running?

22. Cloud and On-Prem Considerations

For managed Redis or Redis-compatible services, verify:

  • Pub/Sub support
  • cluster mode Pub/Sub behavior
  • failover behavior
  • message size limits or practical limits
  • network path latency
  • TLS impact
  • observability metrics
  • client reconnect guidance

For on-prem Redis, verify:

  • Sentinel/Cluster behavior
  • network segmentation
  • firewall timeouts
  • TCP keepalive
  • client reconnect handling
  • monitoring of connected subscribers

23. Security and Privacy Concerns

Pub/Sub messages may appear in logs, traces, or debugging tools.

Avoid:

  • PII in channel names
  • secrets in payloads
  • tokens in messages
  • full customer objects
  • sensitive quote/order payloads
  • unrestricted subscriber access

Use:

  • TLS where required
  • Redis ACL restrictions
  • network isolation
  • sanitized logs
  • minimal payloads
  • stable identifiers

If the payload is sensitive enough to require audit and access control, Pub/Sub may not be the right transport.


24. Observability

Pub/Sub observability is weaker than queue observability because there is no backlog.

Track at the application level:

  • messages published
  • messages received
  • handler success/failure
  • subscriber connected state
  • reconnect count
  • resubscribe count
  • message processing latency
  • malformed message count
  • local cache invalidation count
  • local cache stale read indicators if available

Redis-side signals:

  • connected clients
  • client list
  • pubsub channel count
  • pubsub pattern count
  • command stats for PUBLISH/SUBSCRIBE
  • client output buffer issues

But remember:

No backlog metric exists because Pub/Sub does not store backlog.

25. Cache Invalidation Pattern

A safer invalidation architecture:

flowchart TD A[Write request] --> B[PostgreSQL transaction] B --> C{Commit success?} C -->|No| D[Return error, do not publish] C -->|Yes| E[Delete/update Redis L2 cache] E --> F[PUBLISH invalidation hint] F --> G[Other Java pods receive hint] G --> H[Evict local L1 cache] H --> I[Next read reloads from Redis or PostgreSQL] I --> J[TTL/version protects missed hints]

Important details:

  • publish after DB commit
  • include entity version where possible
  • make local cache entries expire
  • keep Redis L2 TTL
  • make stale window explicit
  • monitor invalidation handler failures

26. Anti-Patterns

Avoid these:

26.1 Durable Business Event via Pub/Sub

OrderSubmitted -> Redis Pub/Sub -> billing service

This is unsafe because billing can miss the event.

26.2 Job Queue via Pub/Sub

PUBLISH job:new payload

If worker is offline, the job disappears.

Use RabbitMQ, Kafka, Redis Streams, or DB-backed queue.

26.3 Infinite Local Cache with Pub/Sub Invalidation Only

Local cache never expires.
Pub/Sub is the only invalidation mechanism.

If one message is missed, stale data can live indefinitely.

26.4 Large Payload Broadcast

PUBLISH channel huge JSON object

This can cause network amplification, memory pressure, logging risk, and slow subscribers.

26.5 Broad Pattern Subscription Without Ownership

PSUBSCRIBE *

This creates noise, security risk, and unclear ownership.


27. Correctness Concerns

Ask:

Can this message be lost?
If yes, is the system still correct?
If no, why are we using Pub/Sub?

Correct Pub/Sub usage assumes message loss is possible.

Design must include:

  • TTL
  • polling fallback if needed
  • versioned state
  • rebuild path
  • durable source of truth
  • eventual refresh

If none of those exist, Pub/Sub is probably being misused.


28. Concurrency Concerns

Pub/Sub does not serialize business operations.

Multiple messages can arrive:

  • close together
  • out of expected business order
  • during rolling deployment
  • while local cache is being read
  • while Redis cache is being refreshed

Consumers should be idempotent.

For cache invalidation:

Evicting the same local key twice is fine.

For state changes:

Do not apply critical state mutation directly from Pub/Sub without version/source-of-truth validation.

29. Performance Concerns

Pub/Sub is fast, but fan-out can amplify work.

One publish to many subscribers means:

1 message -> N subscriber callbacks

Risks:

  • too many subscribers
  • large messages
  • slow callback processing
  • reconnect storm
  • network amplification
  • logging every message at INFO level
  • pattern subscriptions receiving too much noise

Keep messages small and handlers lightweight.


30. Production-Safe Debugging

Useful checks:

PUBSUB CHANNELS
PUBSUB NUMSUB cache:invalidation:quote
PUBSUB NUMPAT
CLIENT LIST
INFO commandstats

Be careful:

MONITOR

MONITOR can be dangerous in production because it streams all commands and adds overhead.

Prefer application metrics and logs with correlation IDs.

Debugging steps:

  1. Confirm publisher emitted message.
  2. Confirm subscriber is connected.
  3. Confirm channel name matches exactly.
  4. Confirm payload version is supported.
  5. Confirm handler did not fail.
  6. Confirm local cache actually evicted.
  7. Confirm fallback TTL/version protects missed messages.

31. Java Implementation Sketch

Publisher abstraction:

public interface CacheInvalidationPublisher {
    void quoteChanged(TenantId tenantId, QuoteId quoteId, long version, CorrelationId correlationId);
}

Subscriber abstraction:

public interface CacheInvalidationListener {
    void start();
    void stop();
    boolean isSubscribed();
}

Handler:

public final class QuoteInvalidationHandler {
    public void handle(QuoteInvalidationMessage message) {
        localQuoteCache.invalidate(message.tenantId(), message.quoteId());
    }
}

Keep Redis Pub/Sub details outside JAX-RS resource classes.


32. PR Review Checklist

When reviewing Redis Pub/Sub usage, ask:

  • Is message loss acceptable?
  • What happens when subscriber is offline?
  • What happens during deployment or pod restart?
  • Is this a notification or a durable business event?
  • Should this be Kafka, RabbitMQ, or Redis Streams instead?
  • Is the channel naming versioned and scoped?
  • Is the payload small and backward compatible?
  • Are subscriber handlers idempotent?
  • Is there local cache TTL or version protection?
  • Are publisher and subscriber metrics available?
  • Is subscriber health exposed?
  • Does the Java client use a dedicated Pub/Sub connection?
  • What happens during Redis failover?
  • Is sensitive data excluded from channel and payload?

33. Internal Verification Checklist

Verify in the internal CSG/team context:

  • Whether Redis Pub/Sub is used at all.
  • Which services publish to Redis channels.
  • Which services subscribe to Redis channels.
  • Whether Pub/Sub is used for cache invalidation, config refresh, notifications, or business events.
  • Whether any Pub/Sub message is treated as durable.
  • Whether Kafka/RabbitMQ would be more appropriate for any current Pub/Sub use case.
  • Whether channel naming convention is documented.
  • Whether payload schema/versioning is documented.
  • Whether subscriber reconnect/resubscribe behavior is tested.
  • Whether local cache has TTL/version fallback for missed invalidation.
  • Whether Pub/Sub metrics exist in Java services.
  • Whether Redis failover behavior has been tested.
  • Whether Pub/Sub payloads contain PII, secrets, tokens, quote/order sensitive data, or tenant-sensitive information.
  • Whether platform/SRE has runbooks for subscriber disconnect or missed invalidation symptoms.

34. Summary

Redis Pub/Sub is useful when you need low-latency broadcast signals.

It is unsafe when you need durable delivery.

Use it for:

hints, notifications, cache invalidation signals, lightweight coordination

Do not use it for:

business-critical events, jobs, audit trails, durable workflows, guaranteed integration

The senior-engineer rule is:

Every Redis Pub/Sub design must explicitly answer what happens when the message is lost.

If the system remains correct, Pub/Sub may be appropriate.

If the system becomes incorrect, use Redis Streams, Kafka, RabbitMQ, or a database-backed pattern instead.

Lesson Recap

You just completed lesson 20 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.