VALKEY-NOTIFICATIONS(7)

πŸ“¦
version 9.0.6 Β· 2 versions
, in fedora 44

🌸 NAME 🌸

valkey-notifications(7) β€” Keyspace notifications. That's the manual-name situation, folded in near the top so you're not confused, bestie. πŸ’–

✨ DESCRIPTION ✨

Keyspace notifications let clients subscribe to Pub/Sub channels so they can receive events that affect the Valkey data set in some way. It's giving "your data set is the main character and you get notifications about its drama." πŸ‘‘

Examples of events that can be received are:

  • All the commands affecting a given key.
  • All the keys receiving an LPUSH operation.
  • All the keys expiring in the database 0.
⚠️ Note: Valkey Pub/Sub is fire and forget. That is, if your Pub/Sub client disconnects, and reconnects later, all the events delivered during the time the client was disconnected are lost. No cap, they do not come back. πŸ’€

πŸ¦‹ Type of events πŸ¦‹

Keyspace notifications are implemented by sending two distinct types of events for every operation affecting the Valkey data space. For instance, a DEL operation targeting the key named mykey in database 0 will trigger the delivering of two messages, exactly equivalent to the following two PUBLISH commands:

PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey

The first channel listens to all the events targeting the key mykey and the other channel listens only to del operation events on the key mykey.

The first kind of event, with the keyspace prefix in the channel, is called a Key-space notification, while the second, with the keyevent prefix, is called a Key-event notification.

In the previous example a del event was generated for the key mykey, resulting in two messages:

  • The Key-space channel receives as message the name of the event.
  • The Key-event channel receives as message the name of the key.

It is possible to enable only one kind of notification in order to deliver just the subset of events we are interested in.

πŸŽ€ Configuration πŸŽ€

By default, keyspace event notifications are disabled because while not very sensible, the feature uses some CPU power. Notifications are enabled using the notify-keyspace-events of valkey.conf or via the CONFIG SET.

Setting the parameter to the empty string disables notifications. In order to enable the feature a non-empty string is used, composed of multiple characters, where every character has a special meaning according to the following table:

  • K β€” Keyspace events, published with __keyspace@<db>__ prefix.
  • E β€” Keyevent events, published with __keyevent@<db>__ prefix.
  • g β€” Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
  • $ β€” String commands
  • l β€” List commands
  • s β€” Set commands
  • h β€” Hash commands
  • z β€” Sorted set commands
  • t β€” Stream commands
  • d β€” Module key type events
  • x β€” Expired events (events generated every time a key expires)
  • e β€” Evicted events (events generated when a key is evicted for maxmemory)
  • m β€” Key miss events (events generated when a key that doesn't exist is accessed)
  • n β€” New key events (Note: not included in the 'A' class)
  • A β€” Alias for "g$lshztxed", so that the "AKE" string means all the events except "m" and "n".

At least K or E should be present in the string, otherwise no event will be delivered regardless of the rest of the string.

For instance to enable just Key-space events for lists, the configuration parameter must be set to Kl, and so forth.

You can use the string KEA to enable most types of events.

πŸ”₯ Events generated by different commands πŸ”₯

Different commands generate different kind of events according to the following list.

  • DEL generates a del event for every deleted key.
  • RENAME generates two events, a rename_from event for the source key, and a rename_to event for the destination key.
  • MOVE generates two events, a move_from event for the source key, and a move_to event for the destination key.
  • COPY generates a copy_to event.
  • MIGRATE generates a del event if the source key is removed.
  • RESTORE generates a restore event for the key.
  • EXPIRE and all its variants (PEXPIRE, EXPIREAT, PEXPIREAT) generate an expire event when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, the key is deleted and only a del event is generated instead.
  • SORT generates a sortstore event when STORE is used to set a new key. If the resulting list is empty, and the STORE option is used, and there was already an existing key with that name, the result is that the key is deleted, so a del event is generated in this condition.
  • SET and all its variants (SETEX, SETNX, GETSET) generate set events. However SETEX will also generate an expire event.
  • MSET generates a separate set event for every key.
  • SETRANGE generates a setrange event.
  • INCR, DECR, INCRBY, DECRBY commands all generate incrby events.
  • INCRBYFLOAT generates an incrbyfloat event.
  • APPEND generates an append event.
  • LPUSH and LPUSHX generates a single lpush event, even in the variadic case.
  • RPUSH and RPUSHX generates a single rpush event, even in the variadic case.
  • RPOP generates an rpop event. Additionally a del event is generated if the key is removed because the last element from the list was popped.
  • LPOP generates an lpop event. Additionally a del event is generated if the key is removed because the last element from the list was popped.
  • LINSERT generates an linsert event.
  • LSET generates an lset event.
  • LREM generates an lrem event, and additionally a del event if the resulting list is empty and the key is removed.
  • LTRIM generates an ltrim event, and additionally a del event if the resulting list is empty and the key is removed.
  • RPOPLPUSH and BRPOPLPUSH generate an rpop event and an lpush event. In both cases the order is guaranteed (the lpush event will always be delivered after the rpop event). Additionally a del event will be generated if the resulting list is zero length and the key is removed.
  • LMOVE and BLMOVE generate an lpop/rpop event (depending on the wherefrom argument) and an lpush/rpush event (depending on the whereto argument). In both cases the order is guaranteed (the lpush/rpush event will always be delivered after the lpop/rpop event). Additionally a del event will be generated if the resulting list is zero length and the key is removed.
  • HSET, HSETNX, HMSET and HSETEX generate a single hset event if the specified fields were added or modified.
  • HINCRBY generates an hincrby event.
  • HINCRBYFLOAT generates an hincrbyfloat event.
  • HEXPIRE and all its variants (HPEXPIRE, HPEXPIRE, HEXPIREAT and HPEXPIREAT) generate a single hexpire event when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, only a single hexpired event is generated and if the hash object has no more items left it will be deleted and a del event is generated as well.
  • HSETEX and HGETEX generate a single hexpire event when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, only a single hexpired event is generated and if the hash object has no more items left it will be deleted and a del event is generated as well.
  • HPERSIST and HGETEX, will generate an hpersist event if at least 1 hash field expiration time was removed.
  • HDEL generates a single hdel event, and an additional del event if the resulting hash is empty and the key is removed.
  • SADD generates a single sadd event, even in the variadic case.
  • SREM generates a single srem event, and an additional del event if the resulting set is empty and the key is removed.
  • SMOVE generates an srem event for the source key, and an sadd event for the destination key.
  • SPOP generates an spop event, and an additional del event if the resulting set is empty and the key is removed.
  • SINTERSTORE, SUNIONSTORE, SDIFFSTORE generate sinterstore, sunionstore, sdiffstore events respectively. In the special case the resulting set is empty, and the key where the result is stored already exists, a del event is generated since the key is removed.
  • ZINCR generates a zincr event.
  • ZADD generates a single zadd event even when multiple elements are added.
  • ZREM generates a single zrem event even when multiple elements are deleted. When the resulting sorted set is empty and the key is generated, an additional del event is generated.
  • ZREMBYSCORE generates a single zrembyscore event. When the resulting sorted set is empty and the key is generated, an additional del event is generated.
  • ZREMBYRANK generates a single zrembyrank event. When the resulting sorted set is empty and the key is generated, an additional del event is generated.
  • ZDIFFSTORE, ZINTERSTORE and ZUNIONSTORE respectively generate zdiffstore, zinterstore and zunionstore events. In the special case the resulting sorted set is empty, and the key where the result is stored already exists, a del event is generated since the key is removed.
  • XADD generates an xadd event, possibly followed by an xtrim event when used with the MAXLEN subcommand.
  • XDEL generates a single xdel event even when multiple entries are deleted.
  • XGROUP CREATE generates an xgroup-create event.
  • XGROUP CREATECONSUMER generates an xgroup-createconsumer event.
  • XGROUP DELCONSUMER generates an xgroup-delconsumer event.
  • XGROUP DESTROY generates an xgroup-destroy event.
  • XGROUP SETID generates an xgroup-setid event.
  • XSETID generates an xsetid event.
  • XTRIM generates an xtrim event.
  • PERSIST generates a persist event if the expiry time associated with the key has been successfully deleted.
  • Every time a key with a time to live associated is removed from the data set because it expired, an expired event is generated.
  • Every time a key is evicted from the data set in order to free memory as a result of the maxmemory policy, an evicted event is generated.
  • Every time a new key is added to the data set, a new event is generated.
IMPORTANT all the commands generate events only if the target key is really modified. For instance an SREM deleting a non-existing element from a Set will not actually change the value of the key, so no event will be generated.

If in doubt about how events are generated for a given command, the simplest thing to do is to watch yourself:

$ valkey-cli config set notify-keyspace-events KEA
$ valkey-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1

okay bestie now open another terminal (yes, a whole second one, you're that girl) and yeet some commands at the Valkey server, then just watch the events roll in like:

"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...

⏰ Timing of expired events πŸ’€

Keys that have a time to live attached get expired by Valkey in two whole ways, and you need to know both:

  • When the key is accessed by a command and turns out to be expired. πŸ™ˆ
  • Via a background system that hunts for expired keys in the background, incrementally, so it can also sweep up the keys that never get accessed at all. 🧹

So the expired events fire when a key is accessed and one of those two systems decides it's expired. Which means β€” and this is the part that gets people β€” there are no guarantees that the Valkey server will manage to generate the expired event at the exact moment the key's time to live hits zero. It's giving whenever, not on the dot. 😭

Since Valkey 9.0, hash fields can have an associated time to live too. πŸŽ€ Hash fields get deleted when you explicitly hand them an expiration time in the past, or via that same background job that's also responsible for expiring keys. And for that exact reason, there are no guarantees that the Valkey server will be able to generate the hexpired event at the moment the hash field's time to live reaches zero either. Same energy, different data type, bestie.

Basically: expired and hexpired events are generated when the Valkey server deletes a key, not when the time to live theoretically reaches zero. So there can be a significant delay between the moment the key's time to live drops to zero and the moment the corresponding event actually shows up. Not a bug, just how it works, no cap. πŸ’…

🌐 Events in a cluster πŸ¦‹

Every single node of a Valkey cluster generates events about its own subset of the keyspace, exactly as described above. Main character energy, but only over their own little corner. πŸ‘‘

BUT β€” and this is the plot twist β€” unlike regular Pub/Sub communication in a cluster, events' notifications are not broadcasted to all nodes. Put differently: keyspace events are node-specific. 🌸

Which means if you want to receive all the keyspace events of a cluster, your clients need to subscribe to each of the nodes. Every one. Yes, all of them. Sorry bestie, that's just the vibe check. 🫢


That's the whole page, you made it, so proud of you fr fr. πŸ’– This one's from Valkey 9.0.0, dated 2025-10-21, and it lives at VALKEY-NOTIFICATIONS(7). Go forth and subscribe responsibly, icon. βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from