Class RedisLockService
-
- All Implemented Interfaces:
public class RedisLockServiceRedis based lock service. Reentrant, read/write locks, deadlock detection
The Redis clock is used as a time source such that all JVMs use the same source. Note: A forward clock jump on the Redis host can let two threads hold the same lock.
A Redis restart (and potential data loss) is detected and handled. However, a failover to a replica - as done by Redis Cluster or Sentinel - is not detected, and recent lock writes might not have been replicated yet. Two threads could then hold the same lock. Must be used only in combination with standalone Redis, without failover.
If a Redis restart is detected (which might have led to (partial) data loss - or not), then the lock is considered lost.
-
-
Constructor Summary
Constructors Constructor Description RedisLockService(RedisConnectionPool connectionPool, RedisPubSubService redisPubSubService, Long lockLeaseTimeSeconds, Long lockLeaseRenewalTimeSeconds, Long pollDelayWhenWaitingForLockMs, Duration connectionPoolTimeout, Long expireLocksWhichShallNotBeKeptSeconds, String lockKeyPrefix, LockServiceJsonHandler lockServiceJsonHandler, Function1<Runnable, Runnable> onNewThreadHandler)
-
Method Summary
Modifier and Type Method Description final List<LockInfo>getLockInfo(Collection<String> lockNames)Fetches the LockInfos for given lockNames, if still available in Redis final <T extends Any> Pair<Boolean, T>tryLock(Collection<Lock> locks, Long timeoutMs, Boolean keepLockDataAfterUse, Function1<Function0<Boolean>, T> protectedCode)Tries to acquire all locks atomically and runs the protected code. -
-
Constructor Detail
-
RedisLockService
RedisLockService(RedisConnectionPool connectionPool, RedisPubSubService redisPubSubService, Long lockLeaseTimeSeconds, Long lockLeaseRenewalTimeSeconds, Long pollDelayWhenWaitingForLockMs, Duration connectionPoolTimeout, Long expireLocksWhichShallNotBeKeptSeconds, String lockKeyPrefix, LockServiceJsonHandler lockServiceJsonHandler, Function1<Runnable, Runnable> onNewThreadHandler)
- Parameters:
connectionPool- the pool to be used for communicating with RedisredisPubSubService- RedisPubSubService used for broadcasting waiters and faster reaction time upon releaseslockLeaseTimeSeconds- duration in seconds, for how long a lock should be marked as taken in Redis (lease time).lockLeaseRenewalTimeSeconds- duration in seconds, for how often the lease time should automatically be extended while the locks are being held.pollDelayWhenWaitingForLockMs- time to wait between attempts to acquire the locks.expireLocksWhichShallNotBeKeptSeconds- expire time in seconds for locks, for which keepLockDataAfterUse (see tryLock) was set to false.lockKeyPrefix- prefix that shall be used for all keys in Redis (namespacing)onNewThreadHandler- each time a new virtual thread is started for renewing the leases of an acquisition, this handler is used to wrap the Runnable.
-
-
Method Detail
-
getLockInfo
final List<LockInfo> getLockInfo(Collection<String> lockNames)
Fetches the LockInfos for given lockNames, if still available in Redis
-
tryLock
final <T extends Any> Pair<Boolean, T> tryLock(Collection<Lock> locks, Long timeoutMs, Boolean keepLockDataAfterUse, Function1<Function0<Boolean>, T> protectedCode)
Tries to acquire all locks atomically and runs the protected code.
While the lock is being held and the protected code is being executed, the lease is automatically renewed to ensure that the lock does not expire. The protected code can use the provided
hasLocklambda to check if the lock is still being held. It should abort if this lambda returns false.The calling thread should preferably be a VirtualThread. It is put to wait (for max timeoutMs) when the lock is currently unavailable, which should allow the JVM to reschedule the carrier thread during this period.
Writers are preferred: a read lock is not granted while another thread waits for the write lock of the same name (also with timeoutMs = 0). Read locks the current thread already holds are not affected.
- Parameters:
locks- that must all be acquired before running the protected codetimeoutMs- max time to wait in case one or more of the requested locks are currently taken/unavailablekeepLockDataAfterUse- if true, the lock data, stored in Redis, is kept after use.protectedCode- the code to be executed once all locks are acquired- Returns:
If the locks were acquired and the protected code was executed, then true+result is returned. If the locks could not be acquired within the timeout, then false+null is returned. That is also the case for a nested call, if one of the locks the current thread already holds was lost meanwhile (see
hasLock) - it is not acquired again
-
-
-
-