Quickstart Guide for App Developers
Page last updated:
This topic provides some sample apps in various languages to demonstrate how to get Redis for Pivotal Platform up and running quickly.
It also highlights the critical components of the apps that allow them to connect to a Redis instance.
Credentials to connect to a Redis for Pivotal Platform instance are passed to the apps as environment variables under VCAP_SERVICES
.
Additionally, this topic includes advice for setting up Spring Sessions with Redis for Pivotal Platform.
Feedback
If you have feedback about this page, or you want more information (other quickstart guides, sample use cases), please send a message to Pivotal Platform Feedback.
Quickstart Apps
All apps using Redis for Pivotal Platform must parse and read the Redis for Pivotal Platform instance credentials from the environment.
The credentials are available to the app once a Redis for Pivotal Platform instance is bound to it and are viewable by typing $cf env {app_name}
.
Prerequisites for these examples include access to a Marketplace with p-redis
or p.redis
.
For reference, p.redis
refers to the Redis service that provides On-Demand instances and p-redis
refers to the Redis service that provides Shared-VM instances.
Any Redis for Pivotal Platform service and plan works with the following examples. Available plans and instance types can be viewed with in the Marketplace.
Quickstart Java App
This is a basic Java app with the capability to get and set keys in Redis and view configuration information. Prerequisites include Maven.
Here we use an on-demand-cache plan of the p.redis
service, but a p-redis
instance also works.
$ git clone git@github.com:colrich/RedisForPCF-Java-Example.git java_redis_app $ cd java_redis_app $ mvn package $ cf create-service p.redis on-demand-cache redis_instance $ cf push redis_example_app -p target/RedisExample-0.0.1-SNAPSHOT.jar $ cf bind-service redis_example_app redis_instance $ cf restage redis_example_app
You can then visit the app in your browser window. The app has three entry points:
- “/” — Gets info about a bound Redis instance
- “/set” — Sets a given key to a given value. E.g., {APP_URL}/set?kn=somekeyname&kv=valuetoset
- “/get” — Gets the value stored at a given key. E.g., {APP_URL}/get?kn=somekeyname
In the application code, the snippet where VCAP_SERVICES is read and parsed is here:
@RequestMapping("/") public RedisInstanceInfo getInfo() { LOG.log(Level.WARNING, "Getting Redis Instance Info in Spring controller..."); // first we need to get the value of VCAP_SERVICES, the environment variable // where connection info is stored String vcap = System.getenv("VCAP_SERVICES"); LOG.log(Level.WARNING, "VCAP_SERVICES content: " + vcap); // now we parse the json in VCAP_SERVICES LOG.log(Level.WARNING, "Using GSON to parse the json..."); JsonElement root = new JsonParser().parse(vcap); JsonObject redis = null; if (root != null) { if (root.getAsJsonObject().has("p.redis")) { redis = root.getAsJsonObject().get("p.redis").getAsJsonArray().get(0).getAsJsonObject(); LOG.log(Level.WARNING, "instance name: " + redis.get("name").getAsString()); } else if (root.getAsJsonObject().has("p-redis")) { redis = root.getAsJsonObject().get("p-redis").getAsJsonArray().get(0).getAsJsonObject(); LOG.log(Level.WARNING, "instance name: " + redis.get("name").getAsString()); } else { LOG.log(Level.SEVERE, "ERROR: no redis instance found in VCAP_SERVICES"); } } // then we pull out the credentials block and produce the output if (redis != null) { JsonObject creds = redis.get("credentials").getAsJsonObject(); RedisInstanceInfo info = new RedisInstanceInfo(); info.setHost(creds.get("host").getAsString()); info.setPort(creds.get("port").getAsInt()); info.setPassword(creds.get("password").getAsString()); // the object will be json serialized automatically by Spring web - we just need to return it return info; } else return new RedisInstanceInfo(); }
Quickstart Node App
This is a basic node app with the capability to get and set keys in Redis and view configuration information.
Prerequisites are the cf cli
and access to a Marketplace with p-redis or p.redis.
Here we use an on-demand-cache plan for the p.redis
service, but a p-redis
instance also works.
$ git clone git@github.com:colrich/RedisForPCF-Node-Example.git node_redis_app $ cd node_redis_app $ cf create-service p.redis on-demand-cache redis_instance $ cf push redis_example_app $ cf bind-service redis_example_app redis_instance $ cf restage redis_example_app
You can then visit the app in your browser window. The app has three entry points:
- “/” — Gets info about bound redis instance
- “/set” — Sets a given key to a given value. E.g., {APP_URL}/set?kn=somekeyname&kv=valuetoset
- “/get” — Gets the value stored at a given key. E.g., {APP_URL}/get?kn=somekeyname
In the application code, the snippet where VCAP_SERVICES is read and parsed is here:
// parses the VCAP_SERVICES env var and looks for redis service instances function getVcapServices() { var vcstr = process.env.VCAP_SERVICES; if (vcstr != null && vcstr.length > 0 && vcstr != '{}') { console.log("found VCAP_SERVICES: " + vcstr) var vcap = JSON.parse(vcstr); if (vcap != null) { if (vcap.hasOwnProperty("p.redis")) { console.log("found redis instance: " + vcap["p.redis"][0].name); return vcap["p.redis"][0] } else if (vcap.hasOwnProperty("p-redis")) { console.log("found redis instance: " + vcap["p-redis"][0].name); return vcap["p-redis"][0] } else { console.log("ERROR: no redis service bound!") } } else { console.log("ERROR: no redis service bound!") } } else { console.log("ERROR: VCAP_SERVICES does not contain a redis block") } return null } // pulls the necessary connection info out of the parsed VCAP_SERVICES block for // the redis connection function getRedisInfo(vcap) { var info = {} info["host"] = vcap["credentials"]["host"] info["port"] = vcap["credentials"]["port"] info["password"] = vcap["credentials"]["password"] return info } // set the port to listen on; for apps in Pivotal Platform it's important to listen on $PORT (usually 8000) app.set('port', (process.env.PORT || 8080)) // this method looks in VCAP_SERVICES for a redis service instance and outputs the // host / port / password info to the response app.get('/', function(request, response) { console.log("Getting Redis connection info from the environment...") var vcap = getVcapServices() if (vcap != null) { var info = getRedisInfo(vcap) console.log("connection info: " + info.host + " / " + info.port + " / " + info.password) response.send("connection info: " + info.host + " / " + info.port + " / " + info.password) } else { console.log("ERROR: VCAP_SERVICES does not contain a redis block or no redis bound") response.send("ERROR: VCAP_SERVICES does not contain a redis block or no redis bound") } })
Quickstart Ruby App
This is a basic ruby app with the capability to get and set keys in Redis and view configuration information.
Here we use an instance of the shared-VM service, but any p-redis
or p.redis
instance works.
$ git clone git@github.com:pivotal-cf/cf-redis-example-app.git ruby_redis_app $ cd ruby_redis_app $ cf create-service p-redis shared-vm redis_instance $ cf push redis_example_app --no-start $ cf bind-service redis_example_app redis_instance $ cf start redis_example_app"
You can then get, set, and delete keys:
$ export APP=redis-example-app.my-cloud-foundry.com $ curl -X PUT $APP/foo -d 'data=bar' success $ curl -X GET $APP/foo bar $ curl -X DELETE $APP/foo success
In the application code, the method where VCAP_SERVICES is read is here:
def redis_credentials service_name = ENV['service_name'] || "redis" if ENV['VCAP_SERVICES'] all_pivotal_redis_credentials = CF::App::Credentials.find_all_by_all_service_tags(['redis', 'pivotal']) if all_pivotal_redis_credentials && all_pivotal_redis_credentials.first all_pivotal_redis_credentials && all_pivotal_redis_credentials.first else redis_service_credentials = CF::App::Credentials.find_by_service_name(service_name) redis_service_credentials end end end
The method where VCAP_SERVICES is parsed is here:
def redis_client @client ||= Redis.new( host: redis_credentials.fetch('host'), port: redis_credentials.fetch('port'), password: redis_credentials.fetch('password'), timeout: 30 ) end
Spring Session with Redis for Pivotal Platform
One common use case of Redis for Pivotal Platform is management of a user’s session information with Spring Session. Spring Session provides an API and implementations with which to manage sessions.
This topic describes how to use Redis for Pivotal Platform as the backend with Spring Session to manage user session information.
This documentation is adopted from the Spring Session docs and extends to include instructions for use with Redis for Pivotal Platform. The document is also adopted from this Spring Session - Spring Boot guide.
Setting Up Spring Session
Updating Dependencies
To use Spring Session, update your dependencies to include spring-session-data-redis. The below example is for Maven.
pom.xml
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.3.1.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
<version>3.5.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.4.RELEASE</version>
</dependency>
</dependencies>
Spring Java Configuration
After adding the required dependencies, we can create our Spring configuration.
The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession
implementation with an implementation backed by Spring Session.
Add the following Spring Configuration:
@EnableRedisHttpSession (1)
public class Config {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(); (2)
}
}
1 | The @EnableRedisHttpSession annotation creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter.
The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session.
In this instance Spring Session is backed by Redis. |
2 | We create a RedisConnectionFactory that connects Spring Session to the Redis Server.
We configure the connection to connect to localhost on the default port (6379)
For more information on configuring Spring Data Redis, refer to the reference documentation. |
Java Servlet Container Initialization
Our Spring Configuration created a Spring Bean named springSessionRepositoryFilter
that implements Filter
.
The springSessionRepositoryFilter
bean is responsible for replacing the HttpSession
with a custom implementation that is backed by Spring Session.
In order for our Filter
to do its magic:
Spring needs to load our
Config
class.We need to ensure that our Servlet Container (i.e. Tomcat) uses our
springSessionRepositoryFilter
for every request.
Fortunately, Spring Session provides a utility class named AbstractHttpSessionApplicationInitializer
, which helps us confirm that these two requirements are met.
The example below shows how to extend AbstractHttpSessionApplicationInitializer
:
src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)
public Initializer() {
super(Config.class); (2)
}
}
The name of our class (Initializer) does not matter. What is important is that we extend AbstractHttpSessionApplicationInitializer
. Doing this achieves the following:
It ensures that the Spring Bean by the name
springSessionRepositoryFilter
is registered with our Servlet Container for every request.It provides a mechanism to easily ensure that Spring loads our
Config
.
Configuring Redis for Pivotal Platform as a Backend
At this stage, Spring Session is now configured to use a Redis instance.
To use a Redis for Pivotal Platform instance, create a session-replication
tag for it.
$ cf update-service INSTANCE_NAME -t session-replication
Other Considerations
The RedisHttpSessionConfiguration
tries to use the Redis CONFIG command.
The CONFIG command is not available due to security recommendations.
This feature can be disabled by exposing ConfigureRedisAction.NO_OP
as a bean:
@Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
However, disabling the configuration means that Redis cannot send namespace notifications.
This functionality is critical for apps that require SessionDestroyedEvent
to be fired to clean up resources,
such as for WebSocket apps to ensure open WebSockets are closed when the HttpSession
expires.
If you want a workaround for this use case, send email to redis-feedback.