Here we explain how you setup and install MemCachier with Flask. While Flask has a built-in caching backend its features are limited to manual caching. For this reason we recommend you use the Flask-Caching
package. Flask-Caching supports memoization, fragment caching (Jinja2 snippets), and whole view caching. For more details about how to use Flask-Caching please refer to its documentation
Flask-Caching
requires the pylibmc
client which relies on the C libmemcached
library. This should be fairly straight-forward to install with your package manager on Linux or Windows. For macOS users, Homebrew provides an easy solution. We also have a blog post for Ubuntu users on how to do this.
Once libmemcached
is installed, then install Flask-Caching
and pylibmc
:
$ pip install Flask-Caching pylibmc
Be sure to update your requirements.txt
file with these new requirements (note that your versions may differ than what’s below):
Flask-Caching==1.4.0
pylibmc==1.5.2
Next, configure your Flask app the following way:
import os
from flask import Flask
from flask_caching import Cache
= Cache()
cache = Flask(__name__)
app
= os.environ.get('MEMCACHIER_SERVERS')
cache_servers if cache_servers == None:
# Fall back to simple in memory cache (development)
={'CACHE_TYPE': 'simple'})
cache.init_app(app, configelse:
= os.environ.get('MEMCACHIER_USERNAME') or ''
cache_user = os.environ.get('MEMCACHIER_PASSWORD') or ''
cache_pass
cache.init_app(app,={'CACHE_TYPE': 'SASLMemcachedCache',
config'CACHE_MEMCACHED_SERVERS': cache_servers.split(','),
'CACHE_MEMCACHED_USERNAME': cache_user,
'CACHE_MEMCACHED_PASSWORD': cache_pass,
'CACHE_OPTIONS': { 'behaviors': {
# Faster IO
'tcp_nodelay': True,
# Keep connection alive
'tcp_keepalive': True,
# Timeout for set/get requests
'connect_timeout': 2000, # ms
'send_timeout': 750 * 1000, # us
'receive_timeout': 750 * 1000, # us
'_poll_timeout': 2000, # ms
# Better failover
'ketama': True,
'remove_failed': 1,
'retry_timeout': 2,
'dead_timeout': 30}}})
The values for MEMCACHIER_SERVERS
, MEMCACHIER_USERNAME
, and MEMCACHIER_PASSWORD
are listed on your cache overview page. Make sure to add them to your environment.
After this, you can start writing cache code in your Flask app:
set("foo", "bar")
cache.print cache.get("foo")
Flask-Caching
provides a decorator to memoize functions. This basically means when the function is called, Flask-Cache will check if the result is in the cache and if it is not it will run the function and save the result to the cache. The memoize decorator works as follows:
@cache.memoize()
def run_expensive_computation(parameter):
# ...
return result
If you need to invalidate stale data you can either delete all memoized results for a function with cache.delete_memoized(run_expensive_computation)
or a result for a specific parameter
with cache.delete_memoized(run_expensive_computation, parameter)
.
Flask-Caching
also provides a decorator to cache views:
@bp.route('/', methods=('GET',))
@cache.cached()
def index():
# ...
return render_template('index.html', ...)
It is important to note that the @cache.cached()
decorator is directly above the definition of the index()
function, i.e., below the @bp.route()
decorator.
The views are cached with a key of the form 'view/' + request.path
. This is important to know if you ever need to invalidate a cached view. You can do that with cache.delete('view/'+path_of_stale_view)
Flask-Caching
provides a Jinja2 control flow statement to cache snippets. The statement has the form {% cache timeout, key, ... %}
where all additional parameters after the key are just appended to the key. In practice this may look as follows:
<!-- Snippet caching example -->
{% for item in list %}
{% cache None, 'item', item['id']|string %}<div>
<!-- Jinja2 snippet that does something with the item -->
</div>
{% endcache %} {% endfor %}
Here the timeout is None
but it can also be a variable that contains a time or an integer denoting seconds.
The cached snippet from the above example can be invalidated (deleted) as follows:
from flask_caching import make_template_fragment_key
= make_template_fragment_key('item', vary_on=[str(item.id)])
key cache.delete(key)
Memcache works well for storing information for short-lived sessions that time out. However, because Memcache is a cache and therefore not persistent, long-lived sessions are better suited to permanent storage options, such as your database.
To store sessions in Memcache, you need Flask-Session.
$ pip install Flask-Session pylibmc
Be sure to update your requirements.txt
file with these new requirements (note that your versions may differ than what’s below):
Flask-Session==0.3.1
pylibmc==1.5.2
Now, configure Flask-Session
:
import os
import pylibmc
from flask import Flask
from flask_session import Session
= Flask(__name__)
app
= os.environ.get('MEMCACHIER_SERVERS').split(',')
servers = os.environ.get('MEMCACHIER_USERNAME')
username = os.environ.get('MEMCACHIER_PASSWORD')
passwd
app.config.from_mapping(= 'memcached',
SESSION_TYPE =
SESSION_MEMCACHED ','), binary=True,
pylibmc.Client(cache_servers.split(=cache_user, password=cache_pass,
username={
behaviors# Faster IO
'tcp_nodelay': True,
# Keep connection alive
'tcp_keepalive': True,
# Timeout for set/get requests
'connect_timeout': 2000, # ms
'send_timeout': 750 * 1000, # us
'receive_timeout': 750 * 1000, # us
'_poll_timeout': 2000, # ms
# Better failover
'ketama': True,
'remove_failed': 1,
'retry_timeout': 2,
'dead_timeout': 30,
})
) Session(app)
You can now use sessions in your app like so:
from flask import session
'key'] = 'value'
session['key', 'not set') session.get(