memory leak when session save model is "always"
Describe the bug version:2.4.3 when a user after logging in , RedisIndexedSessionRepository will add sessionid to redis key: "sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME" type of set, the question is if you set save-mode to always, the sessionId will never be remove from this set after you call request.invalidate()
spring.session.redis.save-mode=always
To Reproduce
- config
spring.session.redis.save-mode=always
- login any user:test, just create sessionId
- logout user:test,call request.invalidate()
- look data in redis ,the sessionId still in "sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:test"
Expected behavior when call request.invalidate() redis remove sessionid from redis set :"sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:test"
** other **
after set spring.session.redis.save-mode=always
in Reproduce3 put all attributes to this.delta every RedisSession instance
if (this.isNew || (RedisIndexedSessionRepository.this.saveMode == SaveMode.ALWAYS)) {
getAttributeNames().forEach((attributeName) -> this.delta.put(getSessionAttrNameKey(attributeName),
cached.getAttribute(attributeName)));
}
then clean sessionId from redis set
private void cleanupPrincipalIndex(RedisSession session) {
String sessionId = session.getId();
Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(session);
String principal = indexes.get(PRINCIPAL_NAME_INDEX_NAME);
if (principal != null) {
this.sessionRedisOperations.boundSetOps(getPrincipalKey(principal)).remove(sessionId);
}
}
but at last call saveDelta() re add sessionId
private void saveDelta() {
if (this.delta.isEmpty()) {
return;
}
String sessionId = getId();
getSessionBoundHashOperations(sessionId).putAll(this.delta);
String principalSessionKey = getSessionAttrNameKey(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String securityPrincipalSessionKey = getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);
if (this.delta.containsKey(principalSessionKey) || this.delta.containsKey(securityPrincipalSessionKey)) {
if (this.originalPrincipalName != null) {
String originalPrincipalRedisKey = getPrincipalKey(this.originalPrincipalName);
RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey)
.remove(sessionId);
}
Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this);
String principal = indexes.get(PRINCIPAL_NAME_INDEX_NAME);
this.originalPrincipalName = principal;
if (principal != null) {
String principalRedisKey = getPrincipalKey(principal);
RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(principalRedisKey)
.add(sessionId);
}
}
this.delta = new HashMap<>(this.delta.size());
Long originalExpiration = (this.originalLastAccessTime != null)
? this.originalLastAccessTime.plus(getMaxInactiveInterval()).toEpochMilli() : null;
RedisIndexedSessionRepository.this.expirationPolicy.onExpirationUpdated(originalExpiration, this);
}
Please help to check whether there is this problem
Apologies for the non-related post, but can you point to a sample using 1. reactive websockets + 2. session
spring.session.redis.save-mode=always
This will cause the memory used of redis server keep growing when session create day by day , but can't be removed after request.invalidate() the memory leak redis key is like :"sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:test"
Apologies for the non-related post, but can you point to a sample using 1. reactive websockets + 2. session
Not only the always mode, but also the on-save mode has the same problem. All sessions under the key "sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:" will never be deleted unless logout is explicitly called.