Skip to content

Add configuration-strategy property to RedisSessionProperties to configure ConfigureRedisAction #17022

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.session.RedisSessionProperties.ConfigurationStrategy;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;

/**
Expand Down Expand Up @@ -62,6 +66,19 @@ public void customize(SessionProperties sessionProperties, RedisSessionPropertie
setCleanupCron(redisSessionProperties.getCleanupCron());
}

@Bean
@ConditionalOnMissingBean
public ConfigureRedisAction configureRedisAction(RedisSessionProperties redisSessionProperties) {
ConfigurationStrategy strategy = redisSessionProperties.getConfigurationStrategy();
if (strategy == ConfigurationStrategy.NOTIFY_KEYSPACE_EVENTS) {
return new ConfigureNotifyKeyspaceEventsAction();
}
if (strategy == ConfigurationStrategy.NO_OP) {
return ConfigureRedisAction.NO_OP;
}
throw new IllegalStateException("Strategy '" + strategy + "' is not supported.");
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -40,6 +40,11 @@ public class RedisSessionProperties {
*/
private RedisFlushMode flushMode = RedisFlushMode.ON_SAVE;

/**
* Allows specifying a strategy for configuring and validating Redis.
*/
private ConfigurationStrategy configurationStrategy = ConfigurationStrategy.NOTIFY_KEYSPACE_EVENTS;

/**
* Cron expression for expired session cleanup job.
*/
Expand Down Expand Up @@ -69,4 +74,29 @@ public void setCleanupCron(String cleanupCron) {
this.cleanupCron = cleanupCron;
}

public ConfigurationStrategy getConfigurationStrategy() {
return this.configurationStrategy;
}

public void setConfigurationStrategy(ConfigurationStrategy configurationStrategy) {
this.configurationStrategy = configurationStrategy;
}

/**
* Allows specifying a strategy for configuring and validating Redis.
*/
public enum ConfigurationStrategy {

/**
* Do nothing.
*/
NO_OP,
/**
* Ensures that Redis Keyspace events for Generic commands and Expired events are
* enabled.
*/
NOTIFY_KEYSPACE_EVENTS

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.boot.autoconfigure.session;

import java.util.Map;

import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;

Expand All @@ -28,13 +30,18 @@
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.testsupport.testcontainers.DisabledWithoutDockerTestcontainers;
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.session.data.mongo.MongoOperationsSessionRepository;
import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.hazelcast.HazelcastSessionRepository;
import org.springframework.session.jdbc.JdbcOperationsSessionRepository;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

/**
* Redis specific tests for {@link SessionAutoConfiguration}.
Expand Down Expand Up @@ -81,6 +88,34 @@ void redisSessionStoreWithCustomizations() {
.run(validateSpringSessionUsesRedis("foo:event:0:created:", RedisFlushMode.IMMEDIATE, "0 0 12 * * *"));
}

@Test
void redisSessionConfigureNoStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withPropertyValues("spring.session.store-type=redis",
"spring.session.redis.configuration-strategy=no_op",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(ConfigureRedisAction.NO_OP.getClass()));
}

@Test
void redisSessionConfigureDefaultStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withPropertyValues("spring.session.store-type=redis",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class,
entry("notify-keyspace-events", "gxE")));
}

@Test
void redisSessionConfigureCustomStrategy() {
this.contextRunner.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class))
.withUserConfiguration(MaxEntriesRedisAction.class)
.withPropertyValues("spring.session.store-type=redis",
"spring.redis.port=" + redis.getFirstMappedPort())
.run(validateStrategy(MaxEntriesRedisAction.class, entry("set-max-intset-entries", "1024")));

}

private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesRedis(
String sessionCreatedChannelPrefix, RedisFlushMode flushMode, String cleanupCron) {
return (context) -> {
Expand All @@ -94,4 +129,25 @@ private ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUs
};
}

private ContextConsumer<AssertableWebApplicationContext> validateStrategy(
Class<? extends ConfigureRedisAction> actionClass, Map.Entry... values) {
return (context) -> {
assertThat(context).hasSingleBean(ConfigureRedisAction.class).hasSingleBean(RedisConnectionFactory.class);
assertThat(context.getBean(ConfigureRedisAction.class)).isInstanceOf(actionClass);
RedisConnection connection = context.getBean(RedisConnectionFactory.class).getConnection();
if (values.length > 0) {
assertThat(connection.getConfig("*")).contains(values);
}
};
}

static class MaxEntriesRedisAction implements ConfigureRedisAction {

@Override
public void configure(RedisConnection connection) {
connection.setConfig("set-max-intset-entries", "1024");
}

}

}