-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Hello SB-integration !
In what version(s) of Spring Integration are you seeing this issue?
Since 6.5.3.RELEASE (SpringBoot BOM parent : >=3.5.7)
6.5.2 tested and ok (SpringBoot BOM parent : <3.5.7)
Describe the bug
With a clustered redis when call the method Lock.unlock()
Using implementation RedisLockRegistry.obtain("myKey") to obtain the lock
To Reproduce
Start a clustred Redis.
Obtain a lock by calling RedisLockRegistry.obtain("myKey")
Call unlock method on obtained previous Lock
Expected behavior
The lock is created and visible with redis client (Like Redis insight).
When call unlock method.
The name of the lock is sent on the dedicated redis channel.
The lock is removed
Sample
For now I can propose you this sample
class Example(private val redisLockRegistry: RedisLockRegistry) {
fun handle(): Void {
val lock = redisLockRegistry.obtain("my-key-for-lock")
val hasLock = lock.tryLock(35, TimeUnit.SECONDS)
if (!hasLock) {
throw NullPointerException("Unable to obtain lock")
}
val result = try {
lock.unlock()
}
}
}
Start with a project with Springboot 3.5.7 (minimum)
I'm working to found a solution to push a repository with a sample. But get in mind the issue can be reproduced only with a redis cluster.
Stacktrace :
Caused by: io.lettuce.core.RedisCommandExecutionException: CROSSSLOT Keys in request don't hash to the same slot
at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:151)
at io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:120)
at io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:124)
at io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:115)
at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:67)
at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:67)
at io.lettuce.core.cluster.ClusterCommand.complete(ClusterCommand.java:50)
at io.lettuce.core.protocol.CommandWrapper.complete(CommandWrapper.java:67)
at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:769)
at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:704)
at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:621)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:868)
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:799)
at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:501)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:399)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:998)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
... 1 common frames omitted\n"
A first investigation on our own :
The stack trace come from here :
Lines 713 to 715 in e73ab48
| return Boolean.TRUE.equals(RedisLockRegistry.this.redisTemplate.execute( | |
| redisScript, List.of(this.lockKey, unLockChannelKeyToUse), | |
| RedisLockRegistry.this.clientId)); |
in 6.5.2
The channel name is pass throught ARGV (arguments array) in 6.5.3 the channel name for unlock is concat with the lock key name and sent as a key .