2

This is a follow up question of: https://github.com/spring-projects/spring-integration/issues/8687

As discussed in the above link, Spring Integration Distributed Lock's concept of TTL is meant for cross-process only, not for threads in the same process.

Later I have tried Redisson, it has a concept of lease time in its RLock:


    /**
     * Tries to acquire the lock with defined <code>leaseTime</code>.
     * Waits up to defined <code>waitTime</code> if necessary until the lock became available.
     *
     * Lock will be released automatically after defined <code>leaseTime</code> interval.
     *
     * @param waitTime the maximum time to acquire the lock
     * @param leaseTime lease time
     * @param unit time unit
     * @return <code>true</code> if lock is successfully acquired,
     *          otherwise <code>false</code> if lock is already set.
     * @throws InterruptedException - if the thread is interrupted
     */
    boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;

https://github.com/redisson/redisson/blob/c2c00a07c279d55d627717fbb290426e19744a65/redisson/src/main/java/org/redisson/api/RLock.java#L55

I think these 2 concepts TTL and lease time are similar (correct me if I am wrong).

But lease time of Redisson works in a consistent way for both cross-process and threads in same process, while TTL of spring integration does not.

The following junit test can reproduce what I mean: https://github.com/cuipengfei/Spikes/blob/22a9896137dd62bda5f030f5a3d33c67fba67310/jpa/spring-jdbc-distributed-lock-issue/src/test/java/com/github/spring/example/LockTest.java#L38C9-L49

docker run -p 6379:6379 -d redis:7.0.12 --requirepass "mypass"

docker run -e POSTGRES_USER=localtest -e POSTGRES_PASSWORD=localtest -e POSTGRES_DB=orders -p 5432:5432 -d postgres:15.3

# start this docker container before running the above junit test

and change mode to compare: https://github.com/cuipengfei/Spikes/blob/master/jpa/spring-jdbc-distributed-lock-issue/src/test/resources/application.properties#L16-L17

lock.registry.name=redisson
# change this line to redis / jdbc / redisson then run test

When running the test in Redis/jdbc mode of spring integration, thread 2 can not get the lock even after TTL.

While running the test in Redisson mode, thread 2 can get the lock after lease time has past, which I think makes more sense conceptually.

What are the design considerations behind TTL/lease time that led to different choices?

htc-stk
  • 15
  • 3
Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87

2 Answers2

1

enter image description here

↑ This is my interpretation.

In the case of Spring Integration, Bob is denied the lock because it values the fact that Alice might still be using it more than the fact that more than 20 seconds have passed. This reduces the chance of interrupting Alice's work.

In contrast, Redisson grants the lock to Bob, prioritizing the expiration of the lock duration over the possibility that Alice is still using it. This provides more consistent behavior for lease time.

Cui Pengfei 崔鹏飞
  • 8,017
  • 6
  • 46
  • 87
0

I believe there are might be other, different approaches to implement distributed locks.

If you look into the RedisLockRegistry of Spring Integration, you'll see that it is similar to the JdbcLockRegistry and there is a local guard with a ReentrantLock. So, all the interactions within the same process follow the standard Java Lock algorithm. As I explained to you in that issue: the TTL is really for losing dead locks in a distributed environment. On the other hand, you cannot predict how long your process is going to hold the lock, so releasing it prematurely because of some leaseTime may lead to inconsistency in your system where you'd expect to be guarded by the lock.

I'm not sure what your goal is with this locks exercise.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • 2
    1. boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) this is its method signature, they have both waitTime and leaseTime. their RLock interface has serveral implementation classes, I took a brief look into these classes, I don't think their Javadoc is wrong – Cui Pengfei 崔鹏飞 Aug 08 '23 at 14:59
  • 2
    2. I disagree with the Opinion-based part. This question is trying to find out the design rationales behind TTL and lease time, and trying to understand what kind of trade offs led to different choices. And I do not think this question had expressed much opinion, as I have stated in the question that the question is Not trying to say which is better – Cui Pengfei 崔鹏飞 Aug 08 '23 at 15:02
  • As I said: I wouldn't expect to have another thread taking the lock over while I'm still in the other thread doing stuff. This Redisson behavior is not what I would rely on. It is a bit sad to not see an explanation of that `lease` behavior in their docs... Seeing so many questions from you on the matter I have feeling that you try to find a justification that Spring Integration behavior is wrong. The `TTL` (`lease`) is a last resort when we have lost a holding process, so another process may treat the lock as broker and take it over. That's why we have also a `RenewableLockRegistry`. – Artem Bilan Aug 08 '23 at 15:14
  • 1
    It is true that I do find redisson's behavior more straight forward and more consistent. But I am not trying to prove Spring Integration behavior is wrong. I would say this is a curiosity based question. It is like when you see two libraries that do similar things, and you wanna find out why have they deisgned their stuff differently – Cui Pengfei 崔鹏飞 Aug 08 '23 at 15:21