Redis doesn't guarantee that expiry happens exactly at expiry time ([1] gives up to a 1 millisecond delay), so if your system assumes that all related keys are removed at exactly the same time it is still broken (although the race window is now tighter).<p>Maybe you could store the related keys in a hash or something?<p>I'm also guilty of trying to use features in redis in ways they weren't really designed for - it's such a fantastic bit of technology that a lot of the time you can still get away with it but it's not redis's fault when it doesn't work!<p>1: <a href="https://redis.io/commands/expire" rel="nofollow">https://redis.io/commands/expire</a>
>The integrity of a set of related keys requires that either all keys exist, or none exist.<p>Using a Key-Value DB to store relational data eh - that never leads to problems.<p>Their solution isn't any better because the API does not guarantee a particular order or atomicity of key expiration - so great that it works for you now[1], but next version may change the behavior.<p>[1] Does it work though? Are you really really sure?
It should be noted that an EXPIREAT triggers a deletion if the timestamp being set is in the past and could lead to an increase in memory and disk pressure during script execution. Worth checking if the behavior there differs in any meaningful way since y'all made the change. EXPIRE usually just marks a key and relies on either subsequent operations to the same key or garbage collection to actually excise the entry and do the subsequent bookkeeping, I believe.<p>It's been a while since I had to deal with this kind of problem though, so please tell me if things are different now.
It seems the article's implication is that they are relying on redis TTL and expiry to guarantee all keys exists or no keys exist, at all times, for a given key set.<p>I never got the impression that Redis gave guarantees on when expired keys were deleted, just that they would be <i>eventually</i>.<p>If the issue is that you want a consistent <i>all or nothing</i>, why not just use a single key to make that determination?
I think the solutions to this problem are:<p>- If the keys are strings, just use a single hashmap and you're done.<p>- If the keys have different types, then you need a Redis module that implements something like `MPEXPIREAT time key1 key2 ...` and then you need to either be able to handle the case where you successfully retrieve key1 but not key2 (because they expired half-way through) or you use a lua script to execute the multi-key access atomically. That said, without the lua script the whole point of having the keys expire at the same time makes less sense, IMO.
I ran into a similar issue and used a hashset of all the related keys with ttls on the individual keys. the hashset would expire making the keys unreachable, and the TTls basically garbages collects the individual keys. anything that required to transact with the set would do so atomically by being wrapped in a lua script.