Skip to content

Commit cc41ea5

Browse files
committed
Ensure Redis session with immediate flush respects defaultMaxInactiveInterval
Resolves: #1409
1 parent e6a88cc commit cc41ea5

File tree

2 files changed

+64
-36
lines changed

2 files changed

+64
-36
lines changed

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

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ public RedisOperations<Object, Object> getSessionRedisOperations() {
418418

419419
@Override
420420
public void save(RedisSession session) {
421-
session.saveDelta();
421+
session.save();
422422
if (session.isNew()) {
423423
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
424424
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
@@ -516,12 +516,13 @@ public void deleteById(String sessionId) {
516516

517517
@Override
518518
public RedisSession createSession() {
519-
RedisSession redisSession = new RedisSession();
520-
if (this.defaultMaxInactiveInterval != null) {
521-
redisSession.setMaxInactiveInterval(
522-
Duration.ofSeconds(this.defaultMaxInactiveInterval));
523-
}
524-
return redisSession;
519+
Duration maxInactiveInterval = Duration
520+
.ofSeconds((this.defaultMaxInactiveInterval != null)
521+
? this.defaultMaxInactiveInterval
522+
: MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS);
523+
RedisSession session = new RedisSession(maxInactiveInterval);
524+
session.flushImmediateIfNecessary();
525+
return session;
525526
}
526527

527528
@Override
@@ -711,14 +712,17 @@ final class RedisSession implements Session {
711712
/**
712713
* Creates a new instance ensuring to mark all of the new attributes to be
713714
* persisted in the next save operation.
715+
*
716+
* @param maxInactiveInterval the amount of time that the {@link Session} should
717+
* be kept alive between client requests.
714718
*/
715-
RedisSession() {
719+
RedisSession(Duration maxInactiveInterval) {
716720
this(new MapSession());
721+
this.cached.setMaxInactiveInterval(maxInactiveInterval);
717722
this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli());
718723
this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds());
719724
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli());
720725
this.isNew = true;
721-
this.flushImmediateIfNecessary();
722726
}
723727

724728
/**
@@ -808,7 +812,7 @@ public void removeAttribute(String attributeName) {
808812

809813
private void flushImmediateIfNecessary() {
810814
if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) {
811-
saveDelta();
815+
save();
812816
}
813817
}
814818

@@ -817,16 +821,20 @@ private void putAndFlush(String a, Object v) {
817821
this.flushImmediateIfNecessary();
818822
}
819823

824+
private void save() {
825+
saveChangeSessionId();
826+
saveDelta();
827+
}
828+
820829
/**
821830
* Saves any attributes that have been changed and updates the expiration of this
822831
* session.
823832
*/
824833
private void saveDelta() {
825-
String sessionId = getId();
826-
saveChangeSessionId(sessionId);
827834
if (this.delta.isEmpty()) {
828835
return;
829836
}
837+
String sessionId = getId();
830838
getSessionBoundHashOperations(sessionId).putAll(this.delta);
831839
String principalSessionKey = getSessionAttrNameKey(
832840
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
@@ -859,30 +867,32 @@ private void saveDelta() {
859867
.onExpirationUpdated(originalExpiration, this);
860868
}
861869

862-
private void saveChangeSessionId(String sessionId) {
863-
if (!sessionId.equals(this.originalSessionId)) {
864-
if (!isNew()) {
865-
String originalSessionIdKey = getSessionKey(this.originalSessionId);
866-
String sessionIdKey = getSessionKey(sessionId);
867-
try {
868-
RedisOperationsSessionRepository.this.sessionRedisOperations
869-
.rename(originalSessionIdKey, sessionIdKey);
870-
}
871-
catch (NonTransientDataAccessException ex) {
872-
handleErrNoSuchKeyError(ex);
873-
}
874-
String originalExpiredKey = getExpiredKey(this.originalSessionId);
875-
String expiredKey = getExpiredKey(sessionId);
876-
try {
877-
RedisOperationsSessionRepository.this.sessionRedisOperations
878-
.rename(originalExpiredKey, expiredKey);
879-
}
880-
catch (NonTransientDataAccessException ex) {
881-
handleErrNoSuchKeyError(ex);
882-
}
870+
private void saveChangeSessionId() {
871+
String sessionId = getId();
872+
if (sessionId.equals(this.originalSessionId)) {
873+
return;
874+
}
875+
if (!isNew()) {
876+
String originalSessionIdKey = getSessionKey(this.originalSessionId);
877+
String sessionIdKey = getSessionKey(sessionId);
878+
try {
879+
RedisOperationsSessionRepository.this.sessionRedisOperations
880+
.rename(originalSessionIdKey, sessionIdKey);
881+
}
882+
catch (NonTransientDataAccessException ex) {
883+
handleErrNoSuchKeyError(ex);
884+
}
885+
String originalExpiredKey = getExpiredKey(this.originalSessionId);
886+
String expiredKey = getExpiredKey(sessionId);
887+
try {
888+
RedisOperationsSessionRepository.this.sessionRedisOperations
889+
.rename(originalExpiredKey, expiredKey);
890+
}
891+
catch (NonTransientDataAccessException ex) {
892+
handleErrNoSuchKeyError(ex);
883893
}
884-
this.originalSessionId = sessionId;
885894
}
895+
this.originalSessionId = sessionId;
886896
}
887897

888898
private void handleErrNoSuchKeyError(NonTransientDataAccessException ex) {

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2018 the original author or authors.
2+
* Copyright 2014-2019 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.
@@ -343,7 +343,8 @@ public void saveExpired() {
343343
@Test
344344
public void redisSessionGetAttributes() {
345345
String attrName = "attrName";
346-
RedisSession session = this.redisRepository.new RedisSession();
346+
RedisSession session = this.redisRepository.new RedisSession(
347+
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
347348
assertThat(session.getAttributeNames()).isEmpty();
348349
session.setAttribute(attrName, "attrValue");
349350
assertThat(session.getAttributeNames()).containsOnly(attrName);
@@ -757,6 +758,23 @@ public void flushModeImmediateCreate() {
757758
.isEqualTo(session.getCreationTime().toEpochMilli());
758759
}
759760

761+
@Test // gh-1409
762+
public void flushModeImmediateCreateWithCustomMaxInactiveInterval() {
763+
given(this.redisOperations.boundHashOps(anyString()))
764+
.willReturn(this.boundHashOperations);
765+
given(this.redisOperations.boundSetOps(anyString()))
766+
.willReturn(this.boundSetOperations);
767+
given(this.redisOperations.boundValueOps(anyString()))
768+
.willReturn(this.boundValueOperations);
769+
this.redisRepository.setDefaultMaxInactiveInterval(60);
770+
this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE);
771+
this.redisRepository.createSession();
772+
Map<String, Object> delta = getDelta();
773+
assertThat(delta.size()).isEqualTo(3);
774+
assertThat(delta.get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR))
775+
.isEqualTo(60);
776+
}
777+
760778
@Test
761779
public void flushModeImmediateSetAttribute() {
762780
given(this.redisOperations.boundHashOps(anyString()))

0 commit comments

Comments
 (0)