-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Extremely rare error due to session expiration date and session storage expiration date being the same. #2786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi, @yu-shiba. This behavior is expected, see #1277. A workaround if you do not want the @Configuration
@EnableSpringHttpSession
public class SessionConfig {
@Bean
SafeSessionRepository<?> repository(RedisConnectionFactory redisConnectionFactory) {
RedisSessionRepository delegate = new RedisSessionRepository(createRedisTemplate(redisConnectionFactory));
return new SafeSessionRepository<>(delegate);
}
private RedisTemplate<String, Object> createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// set the properties accordingly to your needs
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
static class SafeSessionRepository<T extends Session> implements SessionRepository<T> {
private final SessionRepository<T> delegate;
SafeSessionRepository(SessionRepository<T> delegate) {
this.delegate = delegate;
}
@Override
public T createSession() {
return this.delegate.createSession();
}
@Override
public void save(T session) {
try {
this.delegate.save(session);
} catch (IllegalStateException ex) {
// your behavior here
}
}
@Override
public T findById(String id) {
return this.delegate.findById(id);
}
@Override
public void deleteById(String id) {
this.delegate.deleteById(id);
}
}
} I'll close this because, for now, we won't add any configurable delay as a solution for this problem. |
Hi, @marcusdacoregio , #1277 read. Perhaps I should have added the contents of this ticket to the ticket over there. The issue I would like to raise in this ticket is whether it is possible to improve upon the problem caused by the session and session storage expiration date being identical, which is one of the reasons why a session is determined to be invalid. In a case like this, the session expiration date and the session storage expiration date are considered the same, and the session is determined to be an invalidated session. I think the session storage expiration date should be set for session trash cleanup and should have nothing to do with the session expiration date. In my project I try to avoid this problem by delegating RedisTemplate to adjust the @Configuration
public class RedisSessionConfig extends RedisHttpSessionConfiguration {
@Autowired
private SessionProperties sessionProperties;
@Override
protected Duration getMaxInactiveInterval() {
return sessionProperties.getTimeout();
}
@Override
protected RedisTemplate<String, Object> createRedisTemplate() {
return new SkewedRedisTemplate<String, Object>(super.createRedisTemplate(), getMaxInactiveInterval());
}
@RequiredArgsConstructor
public static class SkewedRedisTemplate<K, V> extends RedisTemplate<K, V> {
@Delegate
private final RedisOperations<K, V> delegate;
private final Duration skew;
@Override
public Boolean expire(K key, long timeout, TimeUnit unit) {
var skewedTimeout = skew.plus(timeout, unit.toChronoUnit()).get(unit.toChronoUnit());
return delegate.expire(key, skewedTimeout, unit);
}
@Override
public Boolean expire(K key, Duration timeout) {
return super.expire(key, timeout);
}
@Override
public Boolean expireAt(K key, Date date) {
var skewedDate = DateUtils.addSeconds(date, (int) skew.getSeconds());
return delegate.expireAt(key, skewedDate);
}
@Override
public Boolean expireAt(K key, Instant expireAt) {
return super.expireAt(key, expireAt);
}
@Override
public <T extends Closeable> T executeWithStickyConnection(RedisCallback<T> callback) {
return delegate.executeWithStickyConnection(callback);
}
}
} With implementation of this measure, the possibility of an |
Describe the bug
When running with Redis as session storage for Spring Session, the following exception may occur in rare cases.
IllegalStateException("Session was invalidated")
To Reproduce
To reproduce the problem, access the session before the session timeout, stop the session with debugger until the session storage expires, and then restart the session.
Expected behavior
After investigating this problem, we found that it is caused by session storage expiring between retrieving a session just before the session expires and saving the session.
The current session and session storage expiration are
but given the above lag between when sessions are retrieved and when session storage expiration is updated, we think the session storage expiration should be longer than the session expiration.
Ideally, it should be the session expiration date plus at least the maximum execution time, but since the maximum execution time depends on system requirements, we think it should be configurable in the properties.
Sample
The above reproduction procedure will confirm this, but we will create it if necessary.
The text was updated successfully, but these errors were encountered: