Reputation: 15474
I want to cache DB queries using redis. For now pseudo code in single API endpoint looks like this:
GET /data
I am caching objets that don't change often so I set expiration to 24h for example. The problem is when I want to update such object. The pseudo code looks like this:
PUT /data
The problem is that after new data has been written to cache (or cache has been deleted) then still GET /data
can overwrite new data in cache by old data. This happens when point 4 form GET /data
is executed just after point 2 from PUT /data
.
Is there any mechanism that will prevent overwriting new data with old data in cache?
Upvotes: 4
Views: 4435
Reputation: 50112
The NX approach as @hobbs had suggested still has a race condition. I'd add to it using WATCH/MULTI/EXEC blocks around your GET workflow for transactional-like behavior.
With NX-only approach, there's still a chance that between 3 and 4, a PUT will get in the way.
Upvotes: 5
Reputation: 240639
In the case where the PUT
puts the fresh data in the cache at the same time as it puts it in the database (write-through cache), you can use SET
/ HSET
when writing to the cache from your PUT
, and SETNX
/ HSETNX
when writing to the cache from your GET
. Since the GET
is only going to write to the cache if the key doesn't exist, normally a SETNX
will succeed. But if someone else (possibly a PUT
) came along and set the key in the meantime, the SETNX
will fail because the key already exists, and you'll get the result you want.
In the case where the PUT
just deletes the data in cache to be repopulated by the next GET
, I don't think you can provide any better guarantee than you already have. The data will live for one expiration time after it was retrieved from the database, which isn't strictly wrong, it's just worse than you would like.
Upvotes: 2