Git Product home page Git Product logo

Comments (30)

gdelory avatar gdelory commented on July 26, 2024 10

We are also hitting this issue as soon as 2 process are trying to lock the same resource. This is 100% reproduceable:

const { client } = require('./utils/RedisClient')
const { default: Redlock } = require('redlock')

const redlock = new Redlock(
  [client], {
    driftFactor: 0.01, // multiplied by lock ttl to determine drift time
    retryCount: 300,
    retryDelay: 1000, // time in ms
    retryJitter: 200, // time in ms
    automaticExtensionThreshold: 500, // time in ms
  }
)

const withLock = async (resourceToLock, doSomethingWithLock) => {
  let lock = await redlock.acquire([resourceToLock], 30000)
  let result
  try {
    result = await doSomethingWithLock()
  } finally {
    await lock.release()
  }
  return result
}

const wait = ms => new Promise((resolve) => setTimeout(resolve, ms))

const main = async () => {
  const name = process.argv[2]
  try {
    await withLock('superId', async () => {
      console.log('start wait', name)
      await wait(30000)
      console.log('done waiting', name)
    })
    console.log('all done', name)
    
  } catch (error) {
    console.error(error.message)
  }
  process.exit()
  
}

main()

Result when running twice this process with p1 and p2 name:

start wait p2
done waiting p2
The operation was unable to achieve a quorum during its retry window.

Edit: This seems to happen 100% of the time if the acquire lock time is shorter than the time the function takes to complete, but seems to work when the acquire time is plenty more. This is not an issue if the function releases properly the lock, it might be if it crashes and doesn't though.

wait(30000) with redlock.acquire([resourceToLock], 30000) => crashes
wait(30000) with redlock.acquire([resourceToLock], 300000) => works

from node-redlock.

aduca98 avatar aduca98 commented on July 26, 2024 9

Any status update on the fix? It looks like a few PRs were made (I saw another github thread). where does this stand? I am also having this issue where I do not know the TTL upfront so I need the autoextending and it is giving me problems.

from node-redlock.

bukovacRobert avatar bukovacRobert commented on July 26, 2024 6

Hey everyone! 👋
Is there a fix for this issue yet, or has anyone found a workaround?
Are we all just waiting for the stable v5 release, or is there something I’ve missed? Any info or updates would be super helpful!

from node-redlock.

paulohlips avatar paulohlips commented on July 26, 2024 5

Hi folks, I faced this problem, but was a mistake in my code.

I was trying to aquire and make a set in the same key, as:

const main = async () => {
try {
const lock = await redlock.acquire(['myKey], 1000);
redisClient.set("myKey", "newValue")
await lock.release();
} catch (e) {
console.error(e);
throw e;
}
}

But this way is wrong because we need to aquire a resourceKey like "myLokedResouce:myKey" and then make changes in our key (is tihis exemple "myKey") and after release the lock on "myLokedResouce:myKey". Now my code search by "resourceKey" to know if can makes changes in my "key" like:

const key = "project"
const value = "CONFLICT"
const resource = locks:${key}
const lockTtl = 66000

async function lockAndSet(resource , lockTtl) {
const lock = await redlock.acquire([resource], lockTtl)

try {
await redisSet(key, value)
console.log('Time finished, key unlocked!')
await lock.release()

} catch (e) {
console.log(e)
}
}

lockAndSet(resource, lockTtl)

from node-redlock.

phil-r avatar phil-r commented on July 26, 2024 2

Hey, we also encountered this issue on both v4 and v5.
In our case the problem was, that our lock was expired by the time we tried to release.

Failing code:

// redis and redlock setup is omitted

const wait = async (ms: number) => {
  return new Promise((resolve) => setTimeout(() => resolve(ms), ms));
};

const main = async () => {
  try {
    const lock = await redlock.acquire(['a'], 1000);
    await wait(1500);
    await lock.release();
  } catch (e) {
    console.error(e);
    throw e;
  }
};

main();

Error:

ExecutionError: The operation was unable to achieve a quorum during its retry window.

working code:

// redis, redlock and wait setup is omitted

const main = async () => {
  try {
    const lock = await redlock.acquire(['a'], 1000);
    await lock.extend(1600);
    await wait(1500);
    await lock.release();
  } catch (e) {
    console.error(e);
    throw e;
  }
};

main();

for us switching to redlock.using, increasing lock duration or using lock.extend all worked.

I think the best for the library would be to make lock.release() a noop if it's already expired.

from node-redlock.

BernalCarlos avatar BernalCarlos commented on July 26, 2024 2

Hi folks, I faced this problem, but was a mistake in my code.

I was trying to aquire and make a set in the same key, as:

const main = async () => { try { const lock = await redlock.acquire(['myKey], 1000); redisClient.set("myKey", "newValue") await lock.release(); } catch (e) { console.error(e); throw e; } }

But this way is wrong because we need to aquire a resourceKey like "myLokedResouce:myKey" and then make changes in our key (is tihis exemple "myKey") and after release the lock on "myLokedResouce:myKey". Now my code search by "resourceKey" to know if can makes changes in my "key" like:

const key = "project" const value = "CONFLICT" const resource = locks:${key} const lockTtl = 66000

async function lockAndSet(resource , lockTtl) { const lock = await redlock.acquire([resource], lockTtl)

try { await redisSet(key, value) console.log('Time finished, key unlocked!') await lock.release()

} catch (e) { console.log(e) } }

lockAndSet(resource, lockTtl)

This was also the solution for my case. The DOCS need updating, I've done so on this PR: #291

from node-redlock.

UgurGumushan avatar UgurGumushan commented on July 26, 2024 1

Hi folks, I faced this problem, but was a mistake in my code.

I was trying to aquire and make a set in the same key, as:

const main = async () => { try { const lock = await redlock.acquire(['myKey], 1000); redisClient.set("myKey", "newValue") await lock.release(); } catch (e) { console.error(e); throw e; } }

But this way is wrong because we need to aquire a resourceKey like "myLokedResouce:myKey" and then make changes in our key (is tihis exemple "myKey") and after release the lock on "myLokedResouce:myKey". Now my code search by "resourceKey" to know if can makes changes in my "key" like:

const key = "project" const value = "CONFLICT" const resource = locks:${key} const lockTtl = 66000

async function lockAndSet(resource , lockTtl) { const lock = await redlock.acquire([resource], lockTtl)

try { await redisSet(key, value) console.log('Time finished, key unlocked!') await lock.release()

} catch (e) { console.log(e) } }

lockAndSet(resource, lockTtl)

This worked for me. Thank you.
So this project did not document how to use resource keys. (Please update the *.md if possible)

Summary:
We should not use the key of the locked resource as resource keys and prepend something like "redlock:user1111" and this refers to the lock, like a pointer and not the actual item.

from node-redlock.

MrFabio avatar MrFabio commented on July 26, 2024 1

Solved it using a check for the lock expiration:

const now = new Date().getTime();
if (lock && lock.expiration > now) {
  await lock.release();
}

If the lock is expired (TTL), it is no longer in the cache, so don't release it.

from node-redlock.

paymog avatar paymog commented on July 26, 2024

Downgrading to version 4 for redlock and ioredis solved my issue completely, I guess there's a bug with the v5 implementation.

from node-redlock.

kylecannon avatar kylecannon commented on July 26, 2024

having this same issue too.

from node-redlock.

jskorlol avatar jskorlol commented on July 26, 2024

I have the same problem, is there any solution?

from node-redlock.

paymog avatar paymog commented on July 26, 2024

@jskorlol try downgrading to version 4 of this package and ioredis

from node-redlock.

kylecannon avatar kylecannon commented on July 26, 2024

yeah, the problem is i would really like the lock auto extend functionality.

from node-redlock.

jjm340 avatar jjm340 commented on July 26, 2024

I'm having this problem too, we use redlock v4 to great success so I'm downgrading for now.

from node-redlock.

hlongvu avatar hlongvu commented on July 26, 2024

any update on this, I am having this problem too

from node-redlock.

Dakuan avatar Dakuan commented on July 26, 2024

We are still seeing this intermittently even with redlock.using

from node-redlock.

jketcham avatar jketcham commented on July 26, 2024

I was also running into this on version 5.0.0-beta.2 while using redlock.using, here's the relevant stack trace:

ExecutionError: The operation was unable to achieve a quorum during its retry window.
    at Redlock._execute (file:///workspace/node_modules/redlock/dist/esm/index.js:290:23)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Redlock.acquire (file:///workspace/node_modules/redlock/dist/esm/index.js:207:34)
    at async Redlock.using (file:///workspace/node_modules/redlock/dist/esm/index.js:448:20)
    ... my code ...

With the call to using looking like:

await redlock.using([lockId], 5000, async (signal) => { ... my code ... });

The problem seems to occur when the same resource is trying to be locked multiple times in close succession. Increasing the retryCount and retryDelay (to 30 and 1000 respectively for my setup) prevented the quorum error from throwing, but then I'd still have errors about not being able to extend an already expired lock.

from node-redlock.

eth-limo avatar eth-limo commented on July 26, 2024

Got bitten by this as well

    "ioredis": "^5.2.3",
    "redlock": "^5.0.0-beta.2",

from node-redlock.

shengjie9 avatar shengjie9 commented on July 26, 2024

I have issue too! I have no idea. I read code and find client.evalsha(args) function throw error Error: node_redis: The EVALSHA command contains a invalid argument type.,then I have no idea

from node-redlock.

reinoute avatar reinoute commented on July 26, 2024

I believe this is a bug in the v5 implementation. When you attempt to set a lock using acquire() and the resource is locked, Redlock will throw an ExecutionError, but it should throw a ResourceLockedError (as it did in the previous version).

from node-redlock.

vi93a avatar vi93a commented on July 26, 2024

I was facing same issue but it was because of me passing redis client as undefined. You can debug this issue by logging in error event handler of redlock.

from node-redlock.

manomano avatar manomano commented on July 26, 2024

Downgrading to version 4 for redlock and ioredis solved my issue completely, I guess there's a bug with the v5 implementation.

Can you specify concrete version?

from node-redlock.

EmilSabri avatar EmilSabri commented on July 26, 2024

Hi folks, I faced this problem, but was a mistake in my code.

I was trying to aquire and make a set in the same key, as:

const main = async () => { try { const lock = await redlock.acquire(['myKey], 1000); redisClient.set("myKey", "newValue") await lock.release(); } catch (e) { console.error(e); throw e; } }

But this way is wrong because we need to aquire a resourceKey like "myLokedResouce:myKey" and then make changes in our key (is tihis exemple "myKey") and after release the lock on "myLokedResouce:myKey". Now my code search by "resourceKey" to know if can makes changes in my "key" like:

const key = "project" const value = "CONFLICT" const resource = locks:${key} const lockTtl = 66000

async function lockAndSet(resource , lockTtl) { const lock = await redlock.acquire([resource], lockTtl)

try { await redisSet(key, value) console.log('Time finished, key unlocked!') await lock.release()

} catch (e) { console.log(e) } }

lockAndSet(resource, lockTtl)

This resolved my issues. Be sure to add a resource key ^5.0.0-beta.2

from node-redlock.

BoatsDawn avatar BoatsDawn commented on July 26, 2024

The operation was unable to achieve a quorum during its retry window.
Is there a way to fix this?

Code:

const sleep = (ms) => new Promise((res) => setTimeout(res, ms));

for (let i = 0; i < 30; i++) {
    redlock
        .using(['test'], 10_000, async () => {
            await sleep(200);
            console.log('OK');
        })
        .catch((e) => console.error(e.message));
}

from node-redlock.

ravi9989 avatar ravi9989 commented on July 26, 2024

I also faced the same problem, but the solution is around the duration of lock which you mentioned.
I mean :
You are configuring 400ms as duration of lock
and trying to release the lock at 600th ms[trying to release already expired lock]. Which could cause this issue.

from node-redlock.

ifeLight avatar ifeLight commented on July 26, 2024

So currently, with what is available, to prevent errors, you have to give a timelock beyond the duration of your service.

That is if your service will run for 2 seconds, make it 5s to be safe, so as long the service does not crash, it will notify Redis when it is done for another service to acquire the lock. Or you can use the extend method to extend the lock when your service will take longer time.

from node-redlock.

jsnick avatar jsnick commented on July 26, 2024

I write this because there's maybe someone who's mistaken like me.

First, I wrote my code like

await redlock.acquire([
  'StoreProduct', // table name (static), 
  storeProduct.id, // record id (dynamic),
], 60 * 1000);

but I faced error ...unable to achieve a quorum during its retry window.

and after I read lib codes,
I found this codes

so now, I know my case needs to be fixed like

await redlock.acquire([
  `StoreProduct:${storeProduct.id}`,
], 60 * 1000);

from node-redlock.

divmgl avatar divmgl commented on July 26, 2024

Just stumbled on this now. Downgrading to 4.2.0 was the only solution. As far as I can tell it works with the latest version of ioredis but you'll need to add a @ts-expect-error because the two signatures between the expected version of ioredis and the latest are different.

from node-redlock.

apolenkov avatar apolenkov commented on July 26, 2024

I think it is a bug

If you have any existing lock
than client.evalsha return 0 here

const shaResult = (await client.evalsha(script.hash, keys.length, [

and after this place

if (result !== keys.length) {

return error because lock key is not implemented (result === 0), but you have min one row in keys.length > 0

BUT after return error from here

"The operation was unable to achieve a quorum during its retry window.",

from node-redlock.

apolenkov avatar apolenkov commented on July 26, 2024

for lock error vote === 'against'
image

and after we always return error qurum because skip by this line

if (vote === "for") {

from node-redlock.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.