Redis is a service that can be used to cache requests and queries, so that the time it takes for subsequent requests and queries is reduced.
Before getting into Flask caching with Redis, let's first demonstrate a Flask app with an endpoint that takes 5 seconds to return a response.
from flask import Flask
import time
app = Flask(__name__)
@app.route("/Delay")
def Delay():
time.sleep(5)
return "Hello World"
if __name__ == "__main__":
app.run()
Each time we go to the /Delay endpoint, it should take 5 seconds for "Hello World" to be returned.
Let's use Redis to cache requests to the /Delay endpoint. Let's Install Redis on Docker.
Or you could create an Amazon Web Services (AWS) Redis serverless cluster which should give you a URL such as https://my-redis-cache-abc123.serverless.use1.cache.amazonaws.com:6379.
Or you could create an Amazon Web Services (AWS) Redis dedicated cluster which should give you a URL such as https://my-redis-cluster.abc123.clustercfg.use1.cache.amazonaws.com:6379.
If you go with installing Redis on Docker, the docker container ls command on your Docker system should return something like this which shows that Redis is up and running on port 6379.
~]$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4cf2570d0f8f redis:latest "docker-entrypoint.s…" 50 seconds ago Up 49 seconds 0.0.0.0:6379->6379/tcp redis
We will need to update our Flask app have the flask-caching and redis packages. For example, if running Flask in a UI such as VSCode, the pip install command can be used to install the flask-caching and redis packages.
pip install flask
pip install flask-caching
pip install redis
Or, if running Flask in a Docker container, you can create a Docker image from a Dockerfile that has the flask-caching and redis packages and then use the docker build command to create the Docker image.
FROM tiangolo/uwsgi-nginx-flask:latest
RUN apt-get update -y
RUN pip install --upgrade pip
RUN pip install requests
RUN pip install flask-caching
RUN pip install redis
Let's update main.py to include the Caching stuff, replacing CACHE_REDIS_HOST with the IP address or DNS hostname of your Docker system or the AWS URL.
from flask import Flask
import time
from flask_caching import Cache
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'redis'
app.config['CACHE_REDIS_HOST'] = 'docker.example.com'
app.config['CACHE_REDIS_PORT'] = 6379
app.config['CACHE_REDIS_DB'] = 0
cache = Cache(app)
@app.route("/Foo")
def Foo():
time.sleep(5)
return "Hello"
@app.route("/Bar")
@cache.cached(timeout=60)
def Bar():
time.sleep(5)
return "World"
if __name__ == "__main__":
app.run()
Or instead of using CACHE_REDIS_HOST and CACHE_REDIS_PORT and CACHE_REDIS_DB you can instead go with CACHE_REDIS_URL with "redis://" (single trailing s) to connect to a Redis system that is NOT using SSL/TLS or with "rediss://" (two trailing s) to connect to a Redis system that is using SSL/TLS.
CACHE_REDIS_URL
from flask import Flask
import time
from flask_caching import Cache
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'redis'
app.config['CACHE_REDIS_URL'] = 'redis://docker.example.com:6379'
cache = Cache(app)
@app.route("/Foo")
def Foo():
time.sleep(5)
return "Hello"
@app.route("/Bar")
@cache.cached(timeout=60)
def Bar():
time.sleep(5)
return "World"
if __name__ == "__main__":
app.run()
And then run your Flask app using the Docker image and the updated main.py file.
sudo docker run \
--detach \
--name my-flask-app \
--volume /path/to/main.py:/app/main.py \
--publish 0.0.0.0:12345:80 \
myimage:latest
Let's clear your web browsers cache to ensure the request is not being returned from your browsers cache.
Just like before, each time we go to the /Foo endpoint, it will take 5 seconds for "Hello" to be returned since the /Foo endpoint is NOT being cached.
On the other hand, since the /Bar endpoint is being cached for 60 seconds, if the /Bar endpoint is not currently in Redis cache, it will take 5 seconds for "World" to be returned.
However, once the /Bar endpoint has been requested, there should be a key in Redis for the /Bar endpoint, which can be seen with the redis-cli --scan command.
~]$ sudo docker exec redis redis-cli --scan
flask_cache_view//Bar
And there should no longer be a 5 second delay to return the /Bar endpoint since the request was obtained from Redis cache. Nice!
Almost always, Flask apps are not a single main.py file, and instead are comprised of multiple different files. Let's say your Flask app has a structure like this.
├── main.py
├── my-project (directory)
│ ├── __init__.py
│ ├── views.py
main.py could have the following.
from my-project import app
app = app()
if __name__ == '__main__':
app.run()
And __init__.py could have this.
from flask import Flask
from flask_caching import Cache
cache = Cache()
def app():
app = Flask(__name__)
app.config['CACHE_TYPE'] = 'redis'
app.config['CACHE_REDIS_HOST'] = 'docker.example.com'
app.config['CACHE_REDIS_PORT'] = 6379
app.config['CACHE_REDIS_DB'] = 0
from .views import views
app.register_blueprint(views, url_prefix='/')
cache.init_app(app)
return app
And views.py could have this.
import requests
from flask import Blueprint, request
from . import cache
views = Blueprint('views', __name__)
@app.route("/Bar")
@cache.cached(timeout=60)
def Bar():
time.sleep(5)
return "World"
Did you find this article helpful?
If so, consider buying me a coffee over at