Getting Started with AWS

Building a fast session store for your online applications

with Amazon ElastiCache for Redis

Module 2: Session Caching with Redis

You will learn how to implement a small application using Flask

Overview

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:

 Time to Complete

60-90 minutes

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.

Implementation

  • Basic behavior

    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.

  • Test your connection to Redis

    2.1 — Click on the arrow to display the Redis Cluster details.

    2.1 &mdash; Click on the arrow to display the Redis Cluster details.

    2.2 — Copy the Primary Endpoint.

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

    2.2 &mdash; Copy the Primary Endpoint.

    2.3 — In your EC2 instance, configure the REDIS_URL environment variable.

    syntax: shell

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

    2.4 — From your EC2 instance, enter the Python interactive interpreter:

    syntax: shell

    $ python
    

    2.5 — Now run these commands to test the connection to your Redis node.

    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: 

    Edit inbound rules

    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.

  • Session caching with Redis hashes

    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.

  • Expire sessions

    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.

  • Real use cases and advanced examples

    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.

Was this module helpful?

Thank you
Please let us know what you liked.
Close
Sorry to disappoint you
Is something out-of-date, confusing or inaccurate? Please help us improve this tutorial by providing feedback.
Close