Ensure Redis session with immediate flush respects defaultMaxInactiveInterval

Resolves: #1409
This commit is contained in:
Vedran Pavic
2019-05-13 19:06:35 +02:00
parent e6a88ccf4c
commit cc41ea5271
2 changed files with 65 additions and 37 deletions

View File

@@ -418,7 +418,7 @@ public class RedisOperationsSessionRepository implements
@Override @Override
public void save(RedisSession session) { public void save(RedisSession session) {
session.saveDelta(); session.save();
if (session.isNew()) { if (session.isNew()) {
String sessionCreatedKey = getSessionCreatedChannel(session.getId()); String sessionCreatedKey = getSessionCreatedChannel(session.getId());
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta); this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
@@ -516,12 +516,13 @@ public class RedisOperationsSessionRepository implements
@Override @Override
public RedisSession createSession() { public RedisSession createSession() {
RedisSession redisSession = new RedisSession(); Duration maxInactiveInterval = Duration
if (this.defaultMaxInactiveInterval != null) { .ofSeconds((this.defaultMaxInactiveInterval != null)
redisSession.setMaxInactiveInterval( ? this.defaultMaxInactiveInterval
Duration.ofSeconds(this.defaultMaxInactiveInterval)); : MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
} RedisSession session = new RedisSession(maxInactiveInterval);
return redisSession; session.flushImmediateIfNecessary();
return session;
} }
@Override @Override
@@ -711,14 +712,17 @@ public class RedisOperationsSessionRepository implements
/** /**
* Creates a new instance ensuring to mark all of the new attributes to be * Creates a new instance ensuring to mark all of the new attributes to be
* persisted in the next save operation. * persisted in the next save operation.
*
* @param maxInactiveInterval the amount of time that the {@link Session} should
* be kept alive between client requests.
*/ */
RedisSession() { RedisSession(Duration maxInactiveInterval) {
this(new MapSession()); this(new MapSession());
this.cached.setMaxInactiveInterval(maxInactiveInterval);
this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli()); this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli());
this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds()); this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds());
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli()); this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli());
this.isNew = true; this.isNew = true;
this.flushImmediateIfNecessary();
} }
/** /**
@@ -808,7 +812,7 @@ public class RedisOperationsSessionRepository implements
private void flushImmediateIfNecessary() { private void flushImmediateIfNecessary() {
if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) { if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) {
saveDelta(); save();
} }
} }
@@ -817,16 +821,20 @@ public class RedisOperationsSessionRepository implements
this.flushImmediateIfNecessary(); this.flushImmediateIfNecessary();
} }
private void save() {
saveChangeSessionId();
saveDelta();
}
/** /**
* Saves any attributes that have been changed and updates the expiration of this * Saves any attributes that have been changed and updates the expiration of this
* session. * session.
*/ */
private void saveDelta() { private void saveDelta() {
String sessionId = getId();
saveChangeSessionId(sessionId);
if (this.delta.isEmpty()) { if (this.delta.isEmpty()) {
return; return;
} }
String sessionId = getId();
getSessionBoundHashOperations(sessionId).putAll(this.delta); getSessionBoundHashOperations(sessionId).putAll(this.delta);
String principalSessionKey = getSessionAttrNameKey( String principalSessionKey = getSessionAttrNameKey(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
@@ -859,8 +867,11 @@ public class RedisOperationsSessionRepository implements
.onExpirationUpdated(originalExpiration, this); .onExpirationUpdated(originalExpiration, this);
} }
private void saveChangeSessionId(String sessionId) { private void saveChangeSessionId() {
if (!sessionId.equals(this.originalSessionId)) { String sessionId = getId();
if (sessionId.equals(this.originalSessionId)) {
return;
}
if (!isNew()) { if (!isNew()) {
String originalSessionIdKey = getSessionKey(this.originalSessionId); String originalSessionIdKey = getSessionKey(this.originalSessionId);
String sessionIdKey = getSessionKey(sessionId); String sessionIdKey = getSessionKey(sessionId);
@@ -883,7 +894,6 @@ public class RedisOperationsSessionRepository implements
} }
this.originalSessionId = sessionId; this.originalSessionId = sessionId;
} }
}
private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) { private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) {
if (!"ERR no such key" if (!"ERR no such key"

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2018 the original author or authors. * Copyright 2014-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -343,7 +343,8 @@ public class RedisOperationsSessionRepositoryTests {
@Test @Test
public void redisSessionGetAttributes() { public void redisSessionGetAttributes() {
String attrName = "attrName"; String attrName = "attrName";
RedisSession session = this.redisRepository.new RedisSession(); RedisSession session = this.redisRepository.new RedisSession(
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
assertThat(session.getAttributeNames()).isEmpty(); assertThat(session.getAttributeNames()).isEmpty();
session.setAttribute(attrName, "attrValue"); session.setAttribute(attrName, "attrValue");
assertThat(session.getAttributeNames()).containsOnly(attrName); assertThat(session.getAttributeNames()).containsOnly(attrName);
@@ -757,6 +758,23 @@ public class RedisOperationsSessionRepositoryTests {
.isEqualTo(session.getCreationTime().toEpochMilli()); .isEqualTo(session.getCreationTime().toEpochMilli());
} }
@Test // gh-1409
public void flushModeImmediateCreateWithCustomMaxInactiveInterval() {
given(this.redisOperations.boundHashOps(anyString()))
.willReturn(this.boundHashOperations);
given(this.redisOperations.boundSetOps(anyString()))
.willReturn(this.boundSetOperations);
given(this.redisOperations.boundValueOps(anyString()))
.willReturn(this.boundValueOperations);
this.redisRepository.setDefaultMaxInactiveInterval(60);
this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE);
this.redisRepository.createSession();
Map<String, Object> delta = getDelta();
assertThat(delta.size()).isEqualTo(3);
assertThat(delta.get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR))
.isEqualTo(60);
}
@Test @Test
public void flushModeImmediateSetAttribute() { public void flushModeImmediateSetAttribute() {
given(this.redisOperations.boundHashOps(anyString())) given(this.redisOperations.boundHashOps(anyString()))