I’d like to atomically set all values of a list, just like the regular SET
command.
I need it because the list is to be a cached representation of a database query. I’d like to access the cache in the "paginated" mode by using LRANGE
.
I thought of using RPUSH, but if a race condition occurs, my cache will contain multiple sets of duplicate results one after another, and I wouldn’t like that.
Using RPUSH
in conjunction with LTRIM to the known list length should work most of the time, but it may fail in cases where the data source returned different result sets and we had a race condition on LTRIM
. Of course it’s a lot less likely to happen, but still.
The SORTED SET
with indexes as weights suffers from similar kinds of problems.
Using redis’ transactions seems like an overkill: as far as I’m concerned, they halt all other incoming commands until the transaction is over — and the cached result set may be a chunky one.
Yet, DEL
and RPUSH
in a transaction seems like the only option so far. Is it really?
3
Answers
Yeah, I think I figured it out. It should be a LUA script, since they are atomic:
I haven't tested it yet, but should work. First we delete the array, then we set all its values.
LPUSH and RPUSH is variadic so you can just call either of them with all the values you want to add.
This will happen atomically.
The short answer is it sounds like a transaction would generally be the easiest way to handle this:
However, if your list is enormous, and you are concerned with blocking the Redis server while it’s being populated, your other option would be to use a distributed locking pattern like redlock to lock the key from reads/writes while you populate the list.