Search code examples
redisatomic

How to set redis list values atomically?


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?


Solution

  • The short answer is it sounds like a transaction would generally be the easiest way to handle this:

    MULTI
    DEL list
    RPUSH list item1 item2 item3...
    EXEC
    

    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.