'Redis INCRBY with limits

I'd like to know if there is a way to perform this in redis with a single roundtrip from my app:

For a given key K, its possible value V is any of the integers inside the range [A, B]. Basically, it has an upper and lower boundary.

When an INCRBY or DECRBY command is issued (eg. INCRBY key 10) it will be executed only if the resulting value is not out of bounds.

I need this operation to be atomic, and I wanted to know if there was a way to avoid Lua scripting for this.

Thank you.



Solution 1:[1]

This answer might not be what you expect. But I have to say that Lua scripting is the crystal clear solution.

-- range-incrby.lua key , increment
local key = KEYS[1]
local increment = ARGV[1]
local cnt = redis.call('get', key) or 0
cnt = cnt + increment
if (cnt >= 0 and cnt <= 100) then
    redis.call('set', key, cnt)
    return cnt
end

Also, if the range is [0, 2^N - 1], then you can use BITFIELD command with overflow control to solve the problem.

BITFIELD key OVERFLOW FAIL INCRBY uN 0 increment

However, that seems not your case.

Solution 2:[2]

I have to agree that the Lua script solution is clear and efficient. In that case, another variation taking the limit and decrement as a argument can be implemented as.

local value=redis.call("get", KEYS[1]) or 0
local decrement=tonumber(ARGV[1])
local limit=tonumber(ARGV[2])

if (value - decrement) < limit then value = redis.call("decrby", KEYS[1], value - limit)
else value = redis.call("decrby", KEYS[1], decrement) end
return value

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Filipe Andrade