In order to understand the basic idea behind server-side session caching, you will implement a small application using Flask, a microframework for web development in Python. As the focus will be on the concepts and not the particulars of a given framework and language, you can translate the examples to the web framework and programming language of your choice.

If you want to get started with Flask, follow the installation instructions and the quickstart guide.

Below is a very basic application that lets you login and logout:

syntax: python

import os
from flask import Flask, session, redirect, escape, request

app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', default=None)

@app.route('/')

def index():

    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])

    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])

def login():

    if request.method == 'POST':

        session['username'] = request.form['username']
        return redirect('/')

    return '''
        <form method="post">
        <p><input type=text name=username>
        <p><input type=submit value=Login>
        </form>
    '''

@app.route('/logout')

def logout():

    session.pop('username', None)
    return redirect('/')

The rest of the examples will be based on this snippet. The code for all the examples can be found in this repository.

If you have Flask installed and want to boot this app, copy the code to a file called example-1.py. Then you need to export two environment variables: FLASK_APP should be set to example-1.py, and SECRET_KEY should be set to a random string, for example Y0PJWblKsg1axM4fGW. If you need help setting up the environment variables, check Flask’s quickstart guide.

Once you are all set, run this command:

syntax: shell

$ flask run -h 0.0.0.0 -p 5000 --reload

Then head to http://your_flask_endpoint:5000, where you should see your app running. You need to replace your_flask_endpoint with the Public DNS name of your EC2 instance, as you did in the Requirements.

There are three routes available: “/”, “/login”, and “/logout”. Visit them all in turn and you will get familiar with the basic behavior.

Time to Complete Module: 60 - 90 Minutes


The example uses a cookie to store a username. When you first visit the application, there’s no username stored in the session object. When you go to “/login” and provide a username, the value is stored in a signed cookie and you get redirected to the homepage. Then, if you go to “/logout”, the username is removed from the session and you are back where you started.

You will extend this basic application with server-side sessions, but first let’s make sure you can connect to Redis.



Step 2.1

(Click to enlarge)

Step 2.1

In the examples, each time a Redis endpoint is mentioned you should use the hostname of your Primary Endpoint. 

Step 2.2

(Click to enlarge)

Step 2.2

syntax: shell

$ export REDIS_URL="redis://your_redis_endpoint:6379"

syntax: shell

$ python

syntax: python

>>> import redis
>>> client = redis.Redis.from_url('redis://your_redis_endpoint:6379')
>>> client.ping()

**True**

If it hangs, it means you are being blocked by the Security Group settings. Verify that your EC2 instance has access to the security group assigned to your ElastiCache instance. For example, let’s say your EC2 instance was assigned to the default security group. You can now modify the security group of your Amazon ElastiCache instance and add a Custom TCP rule allowing connections on port 6379 from any instance in the default security group: 

Step 2.5

In Source, you can start typing the name of the security group and you’ll be able to click on the Security Group ID. If you need to learn more about Security Groups, you can check the documentation or the Security Group Rules Reference.


Let’s go back to the example. Now you will introduce some small changes that will allow you to store session data in Redis. Here’s the second example with those changes:

syntax: python

import os
import redis
from flask import Flask, session, redirect, escape, request

app = Flask(__name__)

app.secret_key = os.environ.get('SECRET_KEY', default=None)

# BEGIN NEW CODE - PART 1 #
REDIS_URL = os.environ.get('REDIS_URL')
store = redis.Redis.from_url(REDIS_URL)
# END NEW CODE - PART 1 #

@app.route('/')

def index():

    if 'username' in session:

        # BEGIN NEW CODE - PART 2 #
        username = escape(session['username'])
        visits = store.hincrby(username, 'visits', 1)

    return '''
        Logged in as {0}.<br>
        Visits: {1}
        '''.format(username, visits)
        # END NEW CODE - PART 2 #

    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])

def login():

    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect('/')

    return '''
        <form method="post">
        <p><input type=text name=username>
        <p><input type=submit value=Login>
        </form>'''

@app.route('/logout')

def logout():

    session.pop('username', None)
    return redirect('/')

Now Redis is imported and initialized, and index takes care of incrementing a counter and displaying it to the user.

Note that the Redis command you used for incrementing the counter is HINCRBY. That’s because you are using a Redis hash for each user’s session.


Now you will set a Time to Live (TTL) to the server side session. It’s just one extra line of code, and this snippet will only include the / route.

syntax: python

...
@app.route('/')

def index():

    if 'username' in session:

        username = escape(session['username'])
        visits = store.hincrby(username, 'visits', 1)
        # BEGIN NEW CODE #
        store.expire(username, 10)
        # END NEW CODE #

        return '''
            Logged in as {0}.<br>
            Visits: {1}
            '''.format(username, visits)

    return 'You are not logged in'
...

The key where the session is stored will expire in 10 seconds. It’s a very short TTL, useful only for this example. If you run the application now, you will see how visiting the index updates the Visits counter, but if you let 10 seconds elapse without visiting that page, on the next refresh the counter will be back at 1.


This short example is enough for learning the basics of server side sessions, but in a real world scenario you will do something different: instead of storing the username, you will generate and store a token once a user is authenticated. That token will represent be the Redis key under which all the server side session data will be stored. You may also want to abstract some of the behavior presented here, so that any access to the server side session refreshes the TTL without your intervention. In the repository, you will find an example that provides a SessionStore class that abstracts that behavior.