Redis Cluster TTL and CROSSSLOT: Two Separate Conditions

A TTL disappearing after a cache update and CROSSSLOT from EVALSHA are different failures. One concerns expiry semantics when values change; the other concerns the cluster placement of keys used by a script. Switching to a pipeline does not by itself preserve both contracts.

Slot calculations for three example keys

Python’s standard-library CRC16 calculation produced 8000 for both user:{42}:a and user:{42}:b, and 3937 for user:{43}:a. It hashes the nonempty brace content following the Redis Cluster hash-tag rules. These were not responses from Redis nodes.

import binascii
print(binascii.crc_hqx(b"42", 0) % 16384)
print(binascii.crc_hqx(b"43", 0) % 16384)

A shared tag can colocate related keys, but one tag for every key concentrates load on one slot. Review the script’s KEYS list and actual key access, and first question whether unrelated accounts need to participate in the same atomic operation.

Expiry is a separate update contract

KEEPTTL in the SET reference preserves existing expiry; it does not invent a default TTL for a new key. Distinguish a TTL reading of -2, -1 and a positive value, and define separate policies for creating a missing key and updating an existing one.

In staging, combine expiring, persistent and missing keys with same-slot and different-slot placement. A pipeline with intermediate failures does not provide Lua’s atomic execution semantics. NOSCRIPT concerns the script cache, separately from CROSSSLOT. The calculation here verifies placement rules only, not expiry preservation or atomicity on Redis.