Reputation: 27594
I'd like to perform an atomic GET
in Redis, and if the value returned is equal to some expected value, I'd like to do a SET
, but I want to chain all of this together as one atomic operation. (I'm trying to set a flag that indicates whether any process is writing data to disk, as only one process may be permitted to do so.)
Is it possible to accomplish this with Redis?
I have seen documentation on MULTI
operations but I haven't seen conditional operations i MULTI
operations. Any suggestions others can offer with this would be greatly appreciated!
Upvotes: 7
Views: 17185
Reputation: 135
You can do this by SET command, with these 2 arguments, which according to the docs here:
GET - return the old string stored at key, or nil if key did not exist.
NX - Only set the key if it does not already exist.
Since Redis doesn't execute any command while another command is running - you have the 2 operations in an atomic manner.
Upvotes: 1
Reputation: 4669
I came across this post looking for a similar type of function, but I didn't see any options that appealed to me. I opted instead to write a small module in Rust that provides this exact type of operation:
https://github.com/KennethWilke/redis-setif
With this module you would do this via:
SETIF <key> <expected> <new>
HSETIF <key> <field> <expected> <new>
Upvotes: 1
Reputation: 3460
redis-if - lua script for "conditional transactions". More convenient than WATCH + MULTY.
You can pass any combination of conditions & followed commands as json object:
const Redis = require('ioredis')
const redis = new Redis()
redis.defineCommand('transaction', { lua: require('redis-if').script, numberOfKeys: 0 })
await redis.set('custom-state', 'initialized')
await redis.set('custom-counter', 0)
// this call will change state and do another unrelated operation (increment) atomically
let success = await redis.transaction(JSON.stringify({
if: [
// apply changes only if this process has acquired a lock
[ 'initialized', '==', [ 'sget', 'custom-state' ] ]
],
exec: [
[ 'set', 'custom-state', 'finished' ],
[ 'incr', 'custom-counter' ]
]
}))
With this script we removed all custom scripting from our projects.
Upvotes: 0
Reputation: 27594
I ended up using redlock-py, an implementation of the redlock algorithm that the Redis docs recommend for creating write locks: https://redis.io/topics/distlock. The linked article is fantastic reading for anyone looking to create similar write locks in Redis.
Upvotes: 1
Reputation: 1650
You can do both the GET and set operations on the redis server itself using Lua scripts. They're atomic and allow you to add logic too.
Upvotes: 6