Skip to content

Commit f7e0848

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 3de57dc commit f7e0848

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

@@ -45,10 +44,10 @@ public class RedisMessageStore extends AbstractKeyValueMessageStore implements B
4544

4645
private final RedisTemplate<Object, Object> redisTemplate;
4746

48-
private final boolean unlinkAvailable;
49-
5047
private boolean valueSerializerSet;
5148

49+
private volatile boolean unlinkAvailable = true;
50+
5251
/**
5352
* Construct {@link RedisMessageStore} based on the provided
5453
* {@link RedisConnectionFactory} and default empty prefix.
@@ -74,7 +73,6 @@ public RedisMessageStore(RedisConnectionFactory connectionFactory, String prefix
7473
this.redisTemplate.setKeySerializer(new StringRedisSerializer());
7574
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
7675
this.redisTemplate.afterPropertiesSet();
77-
this.unlinkAvailable = RedisUtils.isUnlinkAvailable(this.redisTemplate);
7876
}
7977

8078
@Override
@@ -135,7 +133,15 @@ protected Object doRemove(Object id) {
135133
Object removedObject = this.doRetrieve(id);
136134
if (removedObject != null) {
137135
if (this.unlinkAvailable) {
138-
this.redisTemplate.unlink(id);
136+
try {
137+
this.redisTemplate.unlink(id);
138+
}
139+
catch (Exception ex) {
140+
logger.warn("The UNLINK command has failed (not supported on the Redis server?); " +
141+
"falling back to the regular DELETE command", ex);
142+
this.unlinkAvailable = false;
143+
this.redisTemplate.delete(id);
144+
}
139145
}
140146
else {
141147
this.redisTemplate.delete(id);
@@ -147,7 +153,15 @@ protected Object doRemove(Object id) {
147153
@Override
148154
protected void doRemoveAll(Collection<Object> ids) {
149155
if (this.unlinkAvailable) {
150-
this.redisTemplate.unlink(ids);
156+
try {
157+
this.redisTemplate.unlink(ids);
158+
}
159+
catch (Exception ex) {
160+
logger.warn("The UNLINK command has failed (not supported on the Redis server?); " +
161+
"falling back to the regular DELETE command", ex);
162+
this.unlinkAvailable = false;
163+
this.redisTemplate.delete(ids);
164+
}
151165
}
152166
else {
153167
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)