Last active
July 12, 2021 16:22
-
-
Save Munawwar/78db6bae5212afef48380c978bd27e47 to your computer and use it in GitHub Desktop.
Redis concurrency control
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const redis = require('redis'); | |
const bluebird = require('bluebird'); | |
const redisClient = redis.createClient({}); | |
bluebird.promisifyAll(Object.getPrototypeOf(redisClient)); | |
const luaScript = ` | |
local newPayload = ARGV[1] | |
local newVersionStr, newData = ARGV[1]:match("^([0-9]+)|(.+)$") | |
local prevVal = redis.call("get", KEYS[1]) or nil | |
if prevVal == nil then | |
return redis.call("set", KEYS[1], "1|" .. newData) | |
end | |
local oldVersionStr, oldData = prevVal:match("^([0-9]+)|(.+)$") | |
local newVersion = tonumber(newVersionStr) | |
local oldVersion = tonumber(oldVersionStr) | |
-- check if version matches before writing | |
if oldVersion == (newVersion - 1) then | |
return redis.call('set', KEYS[1], newPayload) | |
else | |
return nil | |
end | |
`; | |
(async () => { | |
const results = await Promise.all([ | |
redisClient.evalAsync(luaScript, 1, 'cc', '1|{a: 1}'), | |
redisClient.evalAsync(luaScript, 1, 'cc', '1|{b: 2}'), | |
redisClient.evalAsync(luaScript, 1, 'cc', '2|{b: 2}'), | |
]); | |
console.log(results); // potential output [ 'OK', null, 'OK' ] | |
console.log(await redisClient.getAsync('cc')); | |
console.log(await redisClient.delAsync('cc')); | |
})(); |
When you get back null, either show error to user
OR if automatic merge it's possible,
fetch data again, merge new data with old, increase the version number and try to write again.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What should we do when we get
null
?