Redis distributed locks are a very useful primitive in many environments where different processes must operate with shared resources in a mutually exclusive way.
In this story, I'll be focusing on configuring redlock in AWS Lambda so that you can implement Redis distributed lock in your serverless app.
First, you need to make a brief knowledge about how distributed lock works.
- You can refer the official document in redis website.
2. If you want to go deep in this, then you must refer to Martin Kleppmann blog.
3. If you are in a hurry, then you can refer to this short blog.
After getting an idea about this, next step was the implementation.
In my scenario, I have already created a redis in AWS ElastiCache, so that i can use this url and port for creating redis client.
First you need to install redlock and redis module in AWS Lambda.
var redis = require('redis');
var Redlock = require('redlock');
const redisOptions = {
host: "url",
port: "port"
};
var client = redis.createClient(redisOptions);
client.on('connect', function (result) {
console.log("connected");
});
async () => {
try {
var sql = "update query";
var ttl = 4000; //ms
var redlock = new Redlock(
[client],
{
driftFactor: 0.01,
retryCount: 10,
retryDelay: 200,
}
);
await redlock.lock(sql, ttl).then(function (lock) {
// do sql updates
return lock.unlock()
.catch(function (err) {
console.error(err);
});
});
} catch (err) {
console.log(err);
}
};
I have applied lock on sql queries and it can be unlocked using lock.unlock().
New code based on latest npm packages
- Redlock 5.0.0-beta.2
- Using “ioredis” package
import Client from "ioredis";
import Redlock from "redlock";
const client = new Client();
if (!client.evalsha) {
client.evalsha = client.evalSha.bind(client);
}
// Create a Redlock instance
const redlock = new Redlock([client], {
driftFactor: 0.01, // time in ms
retryCount: 1,
retryDelay: 200, // time in ms
retryJitter: 200, // time in ms
automaticExtensionThreshold: 500,
});
// Function to lock and set a JSON value
async function lockAndSetValue() {
const key = "key12";
const ttl = 1000; // Time-to-live for the lock in ms
// Acquire a lock.
let lock = await redlock.acquire(key, ttl);
try {
console.log("Lock acquired!");
await client.call("JSON.SET", key, "$", '{"f1": {"a":1}, "f2":{"a":2}}');
console.log("Waiting some time...");
} finally {
// Release the lock.
console.log("Time finished, key unlocked!");
await lock.release();
}
redlock.on("error", (error) => {
// Ignore cases where a resource is explicitly marked as locked on a client.
if (error instanceof ResourceLockedError) {
return;
}
// Log all other errors.
console.error(error);
});
}
lockAndSetValue();
This sample code is based on my requirement. You can modify according to your scenario.