TCB919
TCB919

Reputation: 123

Gunicorn caching Flask Jinja2 templates when using render_template()

Up until now I have been using render_template() almost exclusively for my flask app routes. render_template() This has worked fine when using flask directly:

<!-- demo_template.html -->
<!doctype html>

<form action="/">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name">
  <input type="submit" value="Submit">
</form>

<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

from flask import Flask, render_template, request, redirect

app = Flask(__name__)
DEBUG = 1
HOST = '0.0.0.0'
PORT = 8080

def append_to_file(filename, self):
    with open(filename, "a") as text_file:
        text_file.write("\n%s" % self)

@app.route('/')
def hello():
    args_dict = dict(request.args)
    if 'name' in args_dict.keys():
        append_to_file('templates/demo_template.html', '<p>'+args_dict['name']+'</p>')
    return render_template('demo_template.html',**args_dict)

if __name__ == '__main__':
    app.run(debug = DEBUG, host=HOST, port=PORT)

Once I put Gunicorn in front of this, the base functionality works, however the appended content (name) does not get returned until the worker has been restarted. It would appear that Gunicorn caches the template.

sudo gunicorn -b 0.0.0.0:8090 app_demo:app -w 1 --log-level=debug --reload

Restarting the worker after each request (--max-requests 1) appears to reload the template and shows the appended content:

sudo gunicorn -b 0.0.0.0:8090 app_demo:app -w 1 --log-level=debug --reload --max-requests 1

Is this a bug within Gunicorn or is this behavior expected. I didn't see anything in the Gunicorn docs regarding this behavior. Is there a way to have gunicorn read the files at render time without needing to restart the worker?

Edit: Ok so now I've found two solutions to this problem.

  1. Use Gunicorns --reload-extra option
    • Fastest
    sudo gunicorn -b 0.0.0.0:8090 app_demo:app -w 1 --log-level=debug --reload --reload-extra templates/demo_template.html
    
  2. Within Flask set app.jinja_env.auto_reload = True
    • Faster than using --max-requests 1, Slower than Using the Gunicorn --reload-extra option
    app = Flask(__name__)
    DEBUG = 1
    HOST = '0.0.0.0'
    PORT = 8080
    app.jinja_env.auto_reload = True
    

Upvotes: 1

Views: 1093

Answers (2)

TCB919
TCB919

Reputation: 123

  1. Use Gunicorns --reload-extra option
    • List of templates to watch
    sudo gunicorn -b 0.0.0.0:8090 app_demo:app -w 1 --log-level=debug --reload --reload-extra templates/demo_template.html
    
  2. Within Flask set app.jinja_env.auto_reload = True
    • Slower than using the Gunicorn --reload-extra option
    app = Flask(__name__)
    DEBUG = 1
    HOST = '0.0.0.0'
    PORT = 8080
    app.jinja_env.auto_reload = True
    

Upvotes: 0

Dave W. Smith
Dave W. Smith

Reputation: 24956

This is probably 100% on the Flask side. Flask doesn't reload templates if you have DEBUG set (unless you set the new TEMPLATES_AUTO_RELOAD option).

When you invoke Flask via gunicorn, __name__ == '__main__' will be False, so app.run() won't be called (it's handled by gunicorn instead). This bypasses the setting of DEBUG via that path.

There are few ways of setting DEBUG outside of app.run(). Consult the Flask docs to see which works best for you.

Upvotes: 1

Related Questions