I need to be able to make a transaction in redis that does the following:
- decrement n value if and only if the result is > 0
- otherwise, do nothing
- deal with arbitrary precision decimal numbers (I need them in a float format)
- be accessible to other processes
Simpler put, it's a "Balance": If I have enough in this field, I can use it, otherwise, no. Sometime, it must decrement many balances
To do this, I made a LUA Script that calculates the result of the decrementation, then modifies the fields with this result. I chose this solution, because:
- it's atomic
- the simpler INCRBYFLOAT does the subtraction no matter the result and doesn't seems have the proper precision
- Used the LUA library http://oss.digirati.com.br/luabignum/
The problems I'm facing:
- The lib used doesn't fit: It's only for integers, and it's too big to send each time (event with evalsha, it's slow)
- How to include third party library when programming Lua script in Redis => following that, I'm pretty stuck concerning the usage of additionnal modules on redis. However, it's from the past, now. How are things now ?
- I'm not event sure if there is a more efficient way to do that ? Any advices on the code itself are welcomed
- Is Redis really a way to fullfill my needs ?
The input, "values" is the following format: Array<{ key: string, field: string, value: string // this is actually a BigNumber, with a string format }>
this.redisClient.eval(`
${luaBigNumbers}
local operations = cjson.decode(KEYS[1])
local isStillValid = true
local test
for k, v in pairs(operations) do
local temp = BigNum.new(redis.call('hget', v.key, v.field))
local res = BigNum.mt.add(temp, BigNum.new(v.value))
if BigNum.mt.lt(res, BigNum.new('0')) then
isStillValid = false
end
end
if isStillValid then
for k, v in pairs(operations) do
local temp = BigNum.new(redis.call('hget',v.key, v.field))
redis.call('hset', v.key, v.field, BigNum.mt.tostring(BigNum.mt.add(temp, BigNum.new(v.value))))
end
end
return tostring(isStillValid)`,
1, JSON.stringify(values), (err, reply) => {
TL;DR: I need to have a shared balance function on Redis, how to do that well ?
Posted in stack exchange if you have an idea of how to implement it https://softwareengineering.stackexchange.com/questions/391529/what-architecture-is-the-most-adapted-for-a-shared-balance-in-nodejs-and-maybe