Skip to content

Commit 3dc0fb5

Browse files
artembilangaryrussell
authored andcommitted
GH-3041: Deprecate RedisUtils.isUnlinkAvailable()
Fixes #3041 Some Redis clients/servers don't allow to perform an `INFO` command, therefore we are not able to determine if we can perform `UNLINK` or not. * Deprecate `RedisUtils.isUnlinkAvailable()` as not reliable source of through; use trial with fallback algorithm in the target logic around `UNLINK` command calls. **Cherry-pick to 5.1.x**
1 parent 554f223 commit 3dc0fb5

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

spring-integration-redis/src/main/java/org/springframework/integration/redis/store/RedisMessageStore.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.springframework.data.redis.serializer.RedisSerializer;
2727
import org.springframework.data.redis.serializer.SerializationException;
2828
import org.springframework.data.redis.serializer.StringRedisSerializer;
29-
import org.springframework.integration.redis.util.RedisUtils;
3029
import org.springframework.integration.store.AbstractKeyValueMessageStore;
3130
import org.springframework.util.Assert;
3231

@@ -47,10 +46,10 @@ public class RedisMessageStore extends AbstractKeyValueMessageStore implements B
4746

4847
private final RedisTemplate<Object, Object> redisTemplate;
4948

50-
private final boolean unlinkAvailable;
51-
5249
private boolean valueSerializerSet;
5350

51+
private volatile boolean unlinkAvailable = true;
52+
5453
/**
5554
* Construct {@link RedisMessageStore} based on the provided
5655
* {@link RedisConnectionFactory} and default empty prefix.
@@ -76,7 +75,6 @@ public RedisMessageStore(RedisConnectionFactory connectionFactory, String prefix
7675
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
7776
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
7877
this.redisTemplate.afterPropertiesSet();
79-
this.unlinkAvailable = RedisUtils.isUnlinkAvailable(this.redisTemplate);
8078
}
8179

8280
@Override
@@ -137,7 +135,15 @@ protected Object doRemove(Object id) {
137135
Object removedObject = this.doRetrieve(id);
138136
if (removedObject != null) {
139137
if (this.unlinkAvailable) {
140-
this.redisTemplate.unlink(id);
138+
try {
139+
this.redisTemplate.unlink(id);
140+
}
141+
catch (Exception ex) {
142+
logger.warn("The UNLINK command has failed (not supported on the Redis server?); " +
143+
"falling back to the regular DELETE command", ex);
144+
this.unlinkAvailable = false;
145+
this.redisTemplate.delete(id);
146+
}
141147
}
142148
else {
143149
this.redisTemplate.delete(id);
@@ -149,7 +155,15 @@ protected Object doRemove(Object id) {
149155
@Override
150156
protected void doRemoveAll(Collection<Object> ids) {
151157
if (this.unlinkAvailable) {
152-
this.redisTemplate.unlink(ids);
158+
try {
159+
this.redisTemplate.unlink(ids);
160+
}
161+
catch (Exception ex) {
162+
logger.warn("The UNLINK command has failed (not supported on the Redis server?); " +
163+
"falling back to the regular DELETE command", ex);
164+
this.unlinkAvailable = false;
165+
this.redisTemplate.delete(ids);
166+
}
153167
}
154168
else {
155169
this.redisTemplate.delete(ids);

spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
*/
7676
public final class RedisLockRegistry implements ExpirableLockRegistry, DisposableBean {
7777

78-
private static final Log logger = LogFactory.getLog(RedisLockRegistry.class);
78+
private static final Log LOGGER = LogFactory.getLog(RedisLockRegistry.class);
7979

8080
private static final long DEFAULT_EXPIRE_AFTER = 60000L;
8181

@@ -97,16 +97,14 @@ public final class RedisLockRegistry implements ExpirableLockRegistry, Disposabl
9797

9898
private final String registryKey;
9999

100-
private final boolean unlinkAvailable;
101-
102100
private final StringRedisTemplate redisTemplate;
103101

104102
private final RedisScript<Boolean> obtainLockScript;
105103

106104
private final long expireAfter;
107105

108106
/**
109-
* An {@link ExecutorService} to call {@link StringRedisTemplate#delete(Object)} in
107+
* An {@link ExecutorService} to call {@link StringRedisTemplate#delete} in
110108
* the separate thread when the current one is interrupted.
111109
*/
112110
private Executor executor =
@@ -140,7 +138,6 @@ public RedisLockRegistry(RedisConnectionFactory connectionFactory, String regist
140138
this.obtainLockScript = new DefaultRedisScript<>(OBTAIN_LOCK_SCRIPT, Boolean.class);
141139
this.registryKey = registryKey;
142140
this.expireAfter = expireAfter;
143-
this.unlinkAvailable = RedisUtils.isUnlinkAvailable(this.redisTemplate);
144141
}
145142

146143
/**
@@ -187,7 +184,7 @@ private final class RedisLock implements Lock {
187184

188185
private final ReentrantLock localLock = new ReentrantLock();
189186

190-
private final boolean unlinkAvailable = RedisLockRegistry.this.unlinkAvailable;
187+
private volatile boolean unlinkAvailable = true;
191188

192189
private volatile long lockedAt;
193190

@@ -321,8 +318,8 @@ public void unlock() {
321318
removeLockKey();
322319
}
323320

324-
if (logger.isDebugEnabled()) {
325-
logger.debug("Released lock; " + this);
321+
if (LOGGER.isDebugEnabled()) {
322+
LOGGER.debug("Released lock; " + this);
326323
}
327324
}
328325
catch (Exception e) {
@@ -335,7 +332,15 @@ public void unlock() {
335332

336333
private void removeLockKey() {
337334
if (this.unlinkAvailable) {
338-
RedisLockRegistry.this.redisTemplate.unlink(this.lockKey);
335+
try {
336+
RedisLockRegistry.this.redisTemplate.unlink(this.lockKey);
337+
}
338+
catch (Exception ex) {
339+
LOGGER.warn("The UNLINK command has failed (not supported on the Redis server?); " +
340+
"falling back to the regular DELETE command", ex);
341+
this.unlinkAvailable = false;
342+
RedisLockRegistry.this.redisTemplate.delete(this.lockKey);
343+
}
339344
}
340345
else {
341346
RedisLockRegistry.this.redisTemplate.delete(this.lockKey);

spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ protected boolean removeEldestEntry(Entry<RedisOperations<?, ?>, Boolean> eldest
5757
* @param redisOperations the {@link RedisOperations} to perform {@code INFO} command.
5858
* @return true or false if {@code UNLINK} Redis command is available or not.
5959
* @throws IllegalStateException when {@code INFO} returns null from the Redis.
60+
* @deprecated since 5.1.8 in favor of explicit trials in the target code.
61+
* The INFO command might not be available on the server, but UNLINK might.
62+
* Will be removed in version 5.3.
6063
*/
64+
@Deprecated
6165
public static boolean isUnlinkAvailable(RedisOperations<?, ?> redisOperations) {
6266
return unlinkAvailable.computeIfAbsent(redisOperations, key -> {
6367
Properties info = redisOperations.execute(

0 commit comments

Comments
 (0)