Skip to content

Commit 180cf62

Browse files
Improve handling of failed rename operation
Consider messages that starts with "ERR no such key". Some Redis clients like Redisson might change the message to include more details Closes gh-1743
1 parent 9343e0b commit 180cf62

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisIndexedSessionRepositoryITests.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2021 the original author or authors.
2+
* Copyright 2014-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,13 +20,15 @@
2020
import java.util.Map;
2121
import java.util.UUID;
2222

23+
import io.lettuce.core.RedisCommandExecutionException;
2324
import org.junit.jupiter.api.BeforeEach;
2425
import org.junit.jupiter.api.Test;
2526
import org.junit.jupiter.api.extension.ExtendWith;
2627

2728
import org.springframework.beans.factory.annotation.Autowired;
2829
import org.springframework.context.annotation.Bean;
2930
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.data.redis.RedisSystemException;
3032
import org.springframework.data.redis.connection.DefaultMessage;
3133
import org.springframework.data.redis.core.RedisOperations;
3234
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -45,8 +47,13 @@
4547
import org.springframework.test.context.ContextConfiguration;
4648
import org.springframework.test.context.junit.jupiter.SpringExtension;
4749
import org.springframework.test.context.web.WebAppConfiguration;
50+
import org.springframework.test.util.ReflectionTestUtils;
4851

4952
import static org.assertj.core.api.Assertions.assertThat;
53+
import static org.mockito.ArgumentMatchers.any;
54+
import static org.mockito.BDDMockito.willThrow;
55+
import static org.mockito.Mockito.reset;
56+
import static org.mockito.Mockito.spy;
5057

5158
/**
5259
* Integration tests for {@link RedisIndexedSessionRepository}.
@@ -682,6 +689,33 @@ void changeSessionIdSaveConcurrently() {
682689
assertThat(this.repository.findById(copy2.getId())).isNull();
683690
}
684691

692+
// gh-1743
693+
@Test
694+
@SuppressWarnings("unchecked")
695+
void saveChangeSessionIdWhenFailedRenameOperationExceptionContainsMoreDetailsThenIgnoreError() {
696+
RedisOperations<Object, Object> sessionRedisOperations = (RedisOperations<Object, Object>) ReflectionTestUtils
697+
.getField(this.repository, "sessionRedisOperations");
698+
RedisOperations<Object, Object> spyOperations = spy(sessionRedisOperations);
699+
ReflectionTestUtils.setField(this.repository, "sessionRedisOperations", spyOperations);
700+
701+
RedisSession toSave = this.repository.createSession();
702+
String sessionId = toSave.getId();
703+
704+
this.repository.save(toSave);
705+
RedisIndexedSessionRepository.RedisSession session = this.repository.findById(sessionId);
706+
this.repository.deleteById(sessionId);
707+
String newSessionId = session.changeSessionId();
708+
709+
RedisSystemException redisSystemException = new RedisSystemException(null,
710+
new RedisCommandExecutionException("ERR no such key. channel: [id: 0xec125091,..."));
711+
willThrow(redisSystemException).given(spyOperations).rename(any(), any());
712+
713+
this.repository.save(session);
714+
assertThat(this.repository.findById(sessionId)).isNull();
715+
assertThat(this.repository.findById(newSessionId)).isNull();
716+
reset(spyOperations);
717+
}
718+
685719
private String getSecurityName() {
686720
return this.context.getAuthentication().getName();
687721
}

spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisIndexedSessionRepository.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2021 the original author or authors.
2+
* Copyright 2014-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,6 +52,7 @@
5252
import org.springframework.session.events.SessionExpiredEvent;
5353
import org.springframework.session.web.http.SessionRepositoryFilter;
5454
import org.springframework.util.Assert;
55+
import org.springframework.util.StringUtils;
5556

5657
/**
5758
* <p>
@@ -870,7 +871,8 @@ private void saveChangeSessionId() {
870871
}
871872

872873
private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) {
873-
if (!"ERR no such key".equals(NestedExceptionUtils.getMostSpecificCause(ex).getMessage())) {
874+
String message = NestedExceptionUtils.getMostSpecificCause(ex).getMessage();
875+
if (!StringUtils.startsWithIgnoreCase(message, "ERR no such key")) {
874876
throw ex;
875877
}
876878
}

0 commit comments

Comments
 (0)