Flask Cache not caching
Asked Answered
S

1

14

I followed a tutorial of Flask-Cache and tried to implement it myself. Given the following example, why would Flask not cache the time?

from flask import Flask
import time

app = Flask(__name__)
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app)

@app.route('/time')
@cache.cached(timeout=50, key_prefix='test')
def test():
   return time.ctime()

Output is always the current time.

It seems like the cache is recreated every single request. What am I doing wrong?

Edit: I execute the following python-file with Python 2.7.6:

def runserver():
    port = int(os.environ.get('PORT', 5000))
    Triangle(app)
    app.run(host='0.0.0.0', port=port, processes=5)


if __name__ == '__main__':
    runserver()
Scarper answered 6/10, 2015 at 17:2 Comment(3)
I can't reproduce this; when running with Flask with the bundled app.run() development server, the time is cached. How are you running this?Boutte
Note that SimpleCache is a global dictionary. If you are using a WSGI server that uses multiprocessing to scale out, you'll get separate copies and they'll appear not to cache.Boutte
Thanks Martijn, I am running it locally and not deploying it to any wsgi server. I added my runscriptScarper
B
25

You are using the SimpleCache setup:

cache = Cache(config={'CACHE_TYPE': 'simple'})

This uses a single global dictionary to hold the cache, and this in turn will only work if you are using a WSGI server that uses one Python interpreter to serve all your WSGI requests. If you use a WSGI server that uses separate child processes to handle requests, you'll get a new copy of that dictionary each time and nothing is cached, effectively.

The code works fine when run with the built-in app.run() development server, given you don't use the processes argument.

Your update shows that you run the server with 5 separate processes. Each process will get its own dictionary, and the cache is not shared between them. Use a different caching backend instead, like filesystem:

cache = Cache(config={'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '/tmp'})
Boutte answered 6/10, 2015 at 17:13 Comment(9)
You are right! What do I have to change if I want to keep the processes argument?Scarper
Use a different backend, one that can be shared between processes. The filesystem is one that doesn't require additional dependencies.Boutte
Thank you so much for the perfect answer! I wouldn't have figured it out by myself!Scarper
for WSGI if I am telling processes from .ini file will app.run(host='0.0.0.0', port=port, processes=5) change the case ? also cache_dir can be visible ??Bandicoot
@BeqaBukhradze: I'm not sure what you are asking, really. It doesn't matter how you are configuring your WSGI server, if you use separate processes you are using separate processes.Boutte
is it better configure it from flask or from uwsgiBandicoot
@BeqaBukhradze: those things would be configured in the WSGI server. If you are using uwsgi as the server, then configure the host, port and concurrency settings there. Flask comes with a built-in WSGI server to ease development, but this server should never be used in production (it is not designed to handle real-world loads).Boutte
@MartijnPieters link Here when calling app.run() can i call app.run(threaded=true) or it is not necessary ?Bandicoot
@BeqaBukhradze: when using uWSGI, that part doesn't run. The if __name__ == '__main__': test is not true in that case. app.run() runs the Flask built-in WSGI server, not uWSGI.Boutte

© 2022 - 2024 — McMap. All rights reserved.