0

I'd like to lock value in the redis with redlock.
But, It's not locked even though lock is done successfully.

This is my test code. Pushed data is 'refId:1234' and lock it for 4 seconds.
So, pop should be done after 4 seconds. But, it's poped after 1 seconds.

const redis = require('ioredis');
const redLock = require('redlock');

// Connect to Redis
const client = redis.createClient( {
    port:6379,
    host:'127.0.0.1',
});

const redlock = new redLock([client]);

let count = 0;
let lockT;
function listPush() {
    let value = 'refId:1234';
    client.rpush('events', value, (err, reply) => {
        if (err) {
            console.error(err);
        } 
        else {   
            let now = Date();
            let time = Date.parse(now);
            console.log('Successfully pushed : ', time);
        }
    }); 
}
function listPop() {
    let ret;
    client.lpop('events', (err, reply) => {
       if (err) {
         console.error(err);
       } else {
         let now = Date();
         let time = Date.parse(now);
         console.log(`Data read from list: ${reply}`, ' ', time);
       }
    });
  }
  
function lockValue(value, ttl) {
    return new Promise((resolve, reject) => {
        redlock.lock(`${value}`, ttl)
            .then((lock) => { 
                let now = Date();
                let time = Date.parse(now);
                console.log("Successfully acquired lock on : ", time);
                resolve(lock);
            })
            .catch((error) => {
                console.error(`Failed to acquire lock on "${value}"`);
                reject(error);
            });
    });
}

listPush();
lockValue("refId:1234", 4000);
setTimeout(listPop, 1000);

This is log:

Successfully pushed :  1676204641000
Successfully acquired lock on :  1676204641000
Data read from list: refId:1234   1676204642000

In the log, data read is done within 1 second after lock is done.
The ttl of the lock is 4 seconds. So, data should be accessible after lock time 4 seconds.

It shows that lock is not working
This is partial of lock instance after locking.

  resource: [ 'refId:1234' ],
  value: 'f9f40e68e9ce3a97fa8b820727317b94',
  expiration: 1676205843381,
  attempts: 1,
  attemptsRemaining: 9

If the expiration value means ttl of lock, it is not matched. It's strange. But, I'm not sure expiration means ttl.

I'm confusing why the redlock is not working well.

Am I misconfigured the redlock and redis for distributed lock? Am I misunderstand operation of redlock?

  • If the value is locked in the redis, the value is not accessible until unlocked.
  • Access is blocking until unlocked and is possible after timout or release lock.
fbyself2011
  • 81
  • 2
  • 9
  • 1
    You have to take lock on every mutation. You `listPush` runs without the lock being taken; that is a potential race condition, of course. – Zazaeil Apr 24 '23 at 18:31
  • You are calling listPop after a 1-second timeout, but your lock has a TTL of 4 seconds. This means that the lock will automatically expire after 4 seconds, regardless of whether your listPop function has been called or not. – Jishan Shaikh May 04 '23 at 20:16

1 Answers1

0

To ensure that the lock is working correctly, you should wait for the full duration of the lock's TTL before attempting to pop the value. You can do this by using the setTimeout to delay the execution of the listPop for the full duration of the lock's TTL, like this:

listPush();
lockValue("refId:1234", 4000).then((lock) => {
  setTimeout(() => {
    listPop();
    lock.unlock().then(() => {
      console.log("Lock released");
      process.exit();
    });
  }, lock.ttl);
});
Jishan Shaikh
  • 1,572
  • 2
  • 13
  • 31