diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java index cc909a798..fa2dd15fa 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java @@ -1281,6 +1281,13 @@ public class LettuceConnection extends AbstractRedisConnection { public void release(StatefulConnection connection) { if (connection.isOpen()) { + + if (connection instanceof StatefulRedisConnection) { + StatefulRedisConnection redisConnection = (StatefulRedisConnection) connection; + if (redisConnection.isMulti()) { + redisConnection.async().discard(); + } + } pool.returnResource((StatefulConnection) connection); } else { pool.returnBrokenResource((StatefulConnection) connection); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java index 3dbdde445..2c2298552 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProvider.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.api.StatefulConnection; +import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.support.AsyncConnectionPoolSupport; import io.lettuce.core.support.AsyncPool; import io.lettuce.core.support.BoundedPoolConfig; @@ -109,7 +110,7 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Red } } - /* + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnectionAsync(java.lang.Class) */ @@ -170,14 +171,27 @@ class LettucePoolingConnectionProvider implements LettuceConnectionProvider, Red + " was either previously returned or does not belong to this connection provider"); } + discardIfNecessary(connection); asyncPool.release(connection).join(); return; } + discardIfNecessary(connection); pool.returnObject(connection); } - /* + private void discardIfNecessary(StatefulConnection connection) { + + if (connection instanceof StatefulRedisConnection) { + + StatefulRedisConnection redisConnection = (StatefulRedisConnection) connection; + if (redisConnection.isMulti()) { + redisConnection.async().discard(); + } + } + } + + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#releaseAsync(io.lettuce.core.api.StatefulConnection) */ diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java new file mode 100644 index 000000000..4b1ebbab2 --- /dev/null +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingConnectionProviderUnitTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.redis.connection.lettuce; + +import static org.mockito.Mockito.*; + +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * Unit tests for {@link LettucePoolingConnectionProvider}. + * + * @author Mark Paluch + */ +@RunWith(MockitoJUnitRunner.class) +public class LettucePoolingConnectionProviderUnitTests { + + @Mock LettuceConnectionProvider connectionProviderMock; + @Mock StatefulRedisConnection connectionMock; + @Mock RedisAsyncCommands commandsMock; + + LettucePoolingClientConfiguration config = LettucePoolingClientConfiguration.defaultConfiguration(); + + @Before + public void before() { + + when(connectionMock.async()).thenReturn(commandsMock); + when(connectionProviderMock.getConnection(any())).thenReturn(connectionMock); + } + + @Test // DATAREDIS-988 + public void shouldReturnConnectionOnRelease() { + + LettucePoolingConnectionProvider provider = new LettucePoolingConnectionProvider(connectionProviderMock, config); + + provider.release(provider.getConnection(StatefulRedisConnection.class)); + + verifyZeroInteractions(commandsMock); + } + + @Test // DATAREDIS-988 + public void shouldDiscardTransactionOnReleaseOnActiveTransaction() { + + LettucePoolingConnectionProvider provider = new LettucePoolingConnectionProvider(connectionProviderMock, config); + when(connectionMock.isMulti()).thenReturn(true); + + provider.release(provider.getConnection(StatefulRedisConnection.class)); + + verify(commandsMock).discard(); + } +}