Skip to content

Instantly share code, notes, and snippets.

@cbeams
Created February 26, 2015 16:48
Show Gist options
  • Save cbeams/f21bc3f27d380cbce5ea to your computer and use it in GitHub Desktop.
Save cbeams/f21bc3f27d380cbce5ea to your computer and use it in GitHub Desktop.
commit 354f3886f2e457463b446f0f0360ec97388b7f67 (HEAD, origin/master, origin/HEAD, master)
Author: Chris Beams <[email protected]>
Date: Thu Feb 26 12:12:04 2015 +0100
Externalize http sessions to Redis when on Heroku
We are now running the site with multiple dyno instances on Heroku,
but Heroku does not support sticky sessions [1]. This means that signed
in users don't stay signed in as Heroku load balances user requests
across these multiple instances.
This commit solves this problem by externalizing the management of HTTP
session data to Redis. We already have several Redis instances connected
to the site on Heroku, so this is a convenient solution anyway.
The externalization of session data is done with a combination of Spring
Session [2], Spring Data Redis [3], and the Heroku Spring Cloud
Connector [4] (we were already using the latter for connecting to
Postgres on Heroku. See DataSourceConfig).
The implementation/configuration seen in this commit (simple as it is)
was derived from the guide for using Spring Session within a Spring Boot
app [5].
Note that sessions are managed in Redis only when the app is deployed on
Heroku. When running the app locally, the normal Tomcat HttpSession
remains in use as it did before this commit. This reduces the overall
complexity of the application by avoiding the need to run a Redis server
locally (or run a Redis server embedded).
To query and manipulate sessions, connect to the redis instance using
`redis-cli` as follows:
$ redis-cli -a <password> -h <redis-host> -p <port>
Query existing sessions:
redis-host:12794> keys 'spring:session:sessions:*'
[...]
29) "spring:session:sessions:7827ad64-037f-4bf4-b1ce-7d3a8b3c3e12"
[...]
Delete a session (i.e., sign a user out):
redis-host:12794> del spring:session:sessions:7827ad64-037f-4bf4-b1ce-7d3a8b3c3e12"
Where the session ID seen above is the value of an individual signed-in
user's `SESSION` cookie value.
[1]: https://devcenter.heroku.com/articles/node-sessions#sessions-and-scaling
[2]: http://docs.spring.io/spring-session/docs/current/reference/html5/
[3]: http://projects.spring.io/spring-data-redis/
[4]: https://github.com/spring-cloud/spring-cloud-connectors/tree/master/spring-cloud-heroku-connector
[5]: http://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot.html
diff --git build.gradle build.gradle
index a8eae9d..4376565 100644
--- build.gradle
+++ build.gradle
@@ -36,6 +36,8 @@ dependencies {
compile 'org.projectlombok:lombok:1.14.8'
compile "com.mandrillapp.wrapper.lutung:lutung:0.0.5"
compile "com.h2database:h2"
+ compile "org.springframework.session:spring-session-data-redis:1.0.0.RELEASE"
+ compile "org.springframework.data:spring-data-redis:1.4.2.RELEASE"
runtime "org.flywaydb:flyway-core:3.1"
runtime "org.postgresql:postgresql:9.3-1102-jdbc41"
testCompile "org.springframework.boot:spring-boot-starter-test"
diff --git src/main/java/com/example/site/config/HttpSessionConfiguration.java src/main/java/com/example/site/config/HttpSessionConfiguration.java
new file mode 100644
index 0000000..5c9c2bc
--- /dev/null
+++ src/main/java/com/example/site/config/HttpSessionConfiguration.java
@@ -0,0 +1,21 @@
+package com.example.site.config;
+
+import org.springframework.cloud.config.java.AbstractCloudConfig;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
+
+import static com.example.site.Profiles.cloud_db;
+
+@Profile(cloud_db)
+@Configuration
+@EnableRedisHttpSession
+class HttpSessionConfiguration extends AbstractCloudConfig {
+
+ @Bean
+ public RedisConnectionFactory redisConnectionFactory() {
+ return connectionFactory().redisConnectionFactory();
+ }
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment