Chapter 16 · Pub/Sub, Keyspace Notifications, and Messaging Tradeoffs

Keyspace/Keyevent Notifications: Configuration, Event Types, Overhead, and Race Conditions

Configure only the keyspace/keyevent notifications needed for an AtlasMart fixture, observe their lossy Pub/Sub delivery, and prove why every signal must be reconciled with current state.

Advanced170–230 minutesKeyspace/keyevent notifications and race conditionsRedis Open Source 8.10.1redis-py 8.1.0Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart wants to refresh an in-process cache whenever a Redis key changes. Keyspace notifications can emit a signal automatically, but they are disabled by default, consume CPU when enabled, and use Pub/Sub delivery. This lesson configures only a narrow event set and proves that the notification is a hint about an event—not an immutable copy of business state.

01

Distinguish keyspace channels from keyevent channels and decode the notify-keyspace-events configuration flags.

02

Save and restore the original notification configuration instead of leaving a global lab change behind.

03

Observe SET/EXPIRE/expired events with bounded fixtures and explain expiration timing without promising an exact deadline.

04

Demonstrate the race between receiving a notification and re-reading the key after a later write.

05

Estimate notification overhead from event rate/selectivity and avoid enabling broad event classes without a measured need.

Exact lab baseline

All Chapter 16 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from pinned Docker image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, endpoint 127.0.0.1:6379, TLS disabled only because traffic is loopback-local, default ACL user disabled, named academy-admin and atlasmart-app users, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data, and no explicit maxmemory/eviction policy. Python examples target redis-py 8.1.0. The Chapter 01 application ACL intentionally does not assume Pub/Sub command permissions, so Pub/Sub/configuration demonstrations use academy-admin until Lesson 5 creates a temporary least-privilege Chapter 16 user. Fixtures stay under atlasmart:ch16:.

1. Two channel families expose the same underlying event differently

A keyspace notification uses channel __keyspace@<db>__:<key> and puts the event name in the payload. A keyevent notification uses channel __keyevent@<db>__:<event> and puts the key name in the payload. Both are ordinary Pub/Sub pushes: if the observer is disconnected, the signal is lost.

Mode Channel answers Payload answers
Keyspace (K) Which key changed? What event happened?
Keyevent (E) What event happened? Which key changed?

2. Notifications are disabled by default for a reason

notify-keyspace-events is empty by default in a normal Redis configuration because generating and publishing event signals uses CPU. The configuration string combines delivery family (K/E) with event classes such as generic commands (g), String commands ($), expired events (x), and others. At least K or E is required or nothing is emitted.

redis-cli · inspect only; do not change yet
CONFIG GET notify-keyspace-events# Record the exact original value. The lab restores it in a finally block.
Scope narrowly

The common KEA example enables a broad event set. This lab uses only the event classes needed for String/generic/expiry evidence and restores the prior configuration afterward.

3. Reproducible listener that restores configuration

Using an administrative client is deliberate because CONFIG SET is operationally privileged. The listener enables KEg$x: keyspace plus keyevent channels, generic events, String events, and expired events. The dollar sign is a Redis configuration flag, not shell interpolation because this example is Python.

Python · narrow notification lab with automatic restore
import time, redisadmin = redis.Redis(host="127.0.0.1", port=6379, username="academy-admin", password="AtlasMart-Admin-Lab-Only-2026", decode_responses=True)old = admin.config_get("notify-keyspace-events").get("notify-keyspace-events", "")ps = admin.pubsub()try:    admin.config_set("notify-keyspace-events", "KEg$x")    ps.psubscribe("__keyspace@0__:atlasmart:ch16:l3:*", "__keyevent@0__:*" )    time.sleep(0.05)    admin.set("atlasmart:ch16:l3:item", "v1")    admin.expire("atlasmart:ch16:l3:item", 2)    end = time.monotonic() + 4    seen = []    while time.monotonic() < end and len(seen) < 4:        m = ps.get_message(ignore_subscribe_messages=True, timeout=0.1)        if m: seen.append((m.get("channel"), m.get("data")))    print("events", seen)    print("current_value", admin.get("atlasmart:ch16:l3:item"))finally:    ps.close()    admin.config_set("notify-keyspace-events", old)    admin.unlink("atlasmart:ch16:l3:item")    print("restored", admin.config_get("notify-keyspace-events"))# Expired-event timing is asynchronous; do not assert an exact millisecond deadline.

4. Event names are not snapshots

A notification tells you that Redis emitted an event such as set, del, expire, or expired. It does not contain a versioned snapshot of the value. By the time a listener handles the push, later writes may already have changed the key. Correct consumers therefore treat the event as “something changed; re-read if needed.”

redis-cli · deterministic race idea
SET atlasmart:ch16:l3:race v1SET atlasmart:ch16:l3:race v2GET atlasmart:ch16:l3:race# A delayed listener may process the first set notification after v2 is already authoritative.

5. Expire versus expired are different events

Setting a time-to-live can emit an expire-class signal about configuring expiration. The later expired event is generated when Redis actually removes the expired key through its expiration mechanisms. Redis expiration is not an exact scheduler; the event should not be used as a hard real-time timer or compliance deadline.

Signal Meaning Do not infer
expire expiration metadata was applied/changed the key is already gone
expired Redis removed an expired key exact wall-clock deletion at TTL=0
del a deletion event occurred why the business entity was deleted without re-reading context

6. The configuration string is an event-volume decision

Every enabled class can generate publications. Enabling broad keyspace events on a high-write server increases CPU work and subscriber traffic. Estimate event rate from the actual command mix and key scope, then measure CPU, network, subscriber callback time, and useful-signal ratio. The notification configuration is global to the Redis server, not scoped to one AtlasMart prefix.

Question before enabling Why it matters
Which event classes are required? Avoid publishing irrelevant traffic
How many writes/expirations per second? Estimate signal volume and CPU/network cost
How many observers? Fan-out multiplies downstream work
What if observer is offline? Signals are lost; reconciliation must exist
Can the observer re-read authoritative state? Needed for race-safe correctness

7. Keyspace notifications share Pub/Sub ACL and delivery boundaries

Observers need Pub/Sub permission for the reserved __keyspace@...__ / __keyevent@...__ channels, while the client performing writes needs key permissions separately. Channel Access Control List (ACL) patterns and key ACL patterns are different security controls. Do not grant &* merely to make an observer work.

ACL nuance

For PSUBSCRIBE, Redis ACL checks require the subscription pattern itself to be permitted appropriately. Design a narrowly matched observer user and verify it with ACL DRYRUN/real subscription in an isolated lab.

8. Version-sensitive extension: subkey notifications

Current Redis documentation also exposes subkey notifications for selected hash-field operations. That is a separate feature surface with its own channel families/configuration and evolving command coverage. Chapter 16 does not make it mandatory for the core keyspace lesson; check the exact target Redis patch/client support before adopting it and keep fallback reconciliation at whole-key/application-state level.

9. Failure/misuse: treating the notification as business truth

Suppose AtlasMart receives __keyevent@0__:set → atlasmart:order:1001 and sends “order paid” without re-reading. A later write may already have changed the order to refunded, or the event may refer to a different field entirely. The repair is to re-read authoritative state and, for durable workflows, process a versioned Stream/broker event instead of inferring business meaning from a generic Redis mutation signal.

Safe interpretation

Keyspace/keyevent notifications are excellent cache-invalidation/wake-up hints. They are weak business-domain events because they describe Redis mutations, not an immutable application event contract.

10. Verification checklist

  • The original notify-keyspace-events value was captured and restored.
  • Only bounded Chapter 16 keys were changed.
  • Both keyspace and keyevent channel shapes were explained.
  • The listener re-read current state instead of trusting the push as a snapshot.
  • Expiration timing was treated as asynchronous rather than exact.
redis-cli · bounded Chapter 16 cleanup
UNLINK atlasmart:ch16:l3:race

11. Production judgment

Enable notifications only for a measured need such as cache invalidation, live operational hints, or lightweight observability where loss is acceptable. Avoid broad classes on high-write servers without load testing. Configuration changes should be version-controlled and rollout-safe; in managed Redis, CONFIG permissions/options may differ. Replication/failover do not turn Pub/Sub notifications into a durable log, so every correctness-sensitive observer needs reconciliation.

Check your understanding

  1. Why are notifications disabled by default?
  2. What is the difference between keyspace and keyevent channels?
  3. Why re-read after receiving a notification?
  4. Does expired mean exact TTL deadline execution?
  5. Why restore notify-keyspace-events after the lab?
Review the answers

Generating event notifications consumes CPU and can create significant downstream traffic.

Keyspace channels identify the key and payload the event; keyevent channels identify the event and payload the key.

The push is not a value snapshot and later writes may already have changed state.

No. Redis expiration is not an exact scheduler.

It is a server-global configuration that could add overhead/noise for unrelated workloads.

12. Summary and next step

Keyspace notifications automate signal generation but inherit Pub/Sub loss and race semantics. Lesson 4 now compares that ephemeral model with Redis Streams and external brokers so replay, consumer state, ordering, and durability are chosen explicitly rather than by habit.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.