0

I'm calling a Flask api, run by gunicorn and which is served out by nginx all on a linux box viretal env

When I use curl or postman to test I get 1 of 4 responses randomly each time I run - but mostly response 2 below

Here's my flask api py file. I'm new to this so excuse any errors:

app = Flask(__name__)
now = datetime.now()
timestamp=str(now.strftime("%Y-%m-%d %H:%M"))

# assignes route for POSTING JSON requests
@app.route('/api/v1.0/my-api', methods=['POST'])
#@requires_auth
def runscope():
    if request.method == 'POST':
        in_json = request.json
    in_json["api_datetime"] = timestamp
    json_to_file(in_json)
        return timestamp + "New msg log file success!" 


# assigns route for the default GET request
@app.route('/')
def index():
    return 'test on the index'  


if __name__ == "__main__":
    app.debug = True
    application.run()

# function to drop request data to file
def json_to_file(runscope_json):
    with open('data/data.json', 'a') as outfile:
            json.dump(runscope_json, outfile, indent=2)

So when I run the test below several times in a row

curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' http://localhost:8000/api/v1.0/my-api

I get either 1. Response: "New msg log file success!" with the json getting to the file i specified

OR

  1. Response: "log file success!" which was in an old version of the python code above! The data gets to the file but without the timestamp as the old code didn't have it

OR

  1. "Not Found The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."

OR

  1. { "message": "Authenticate." } which is a response I had in another OLD version of the code!

Note: I do a "gunicorn my-api:app" and a nginx restart if I changed the code, making sure to manually delete the .pyc file first

Can anyone help out? Wheres it getting the old code responses from? Why is it intermittent, giving me the expected new code response only sometimes?

Jaffer Wilson
  • 7,029
  • 10
  • 62
  • 139
amartinez
  • 169
  • 2
  • 14

2 Answers2

2

Did you try to add cache-related headers to your responses? Something like:

# example code
@app.route('/api/v1.0/my-api', methods=['POST'])
def runscope():
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    # rest of the code...

for a specific Flask route...

Or if you want to disable cache for all requests:

# example code
@app.after_request
def add_header(response):
    response.cache_control.max_age = 60
    if 'Cache-Control' not in response.headers:
        response.headers['Cache-Control'] = 'no-store'
    return response
errata
  • 5,695
  • 10
  • 54
  • 99
  • Its does seem like a cache issue - I tried those headers but I got this error response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' NameError: global name 'response' is not defined – amartinez May 31 '17 at 13:25
  • Ah yes, it was just an example code... You should handle it specifically for your use case... I updated my answer with a more general solution too... – errata May 31 '17 at 13:29
  • Thank you. I tried various variations of the cache fix but hit a wall so I went and defined a new route "my-api1" and it solved the "old code" issue. So I get the correct response now. This is a workable work-around for now. – amartinez May 31 '17 at 14:47
  • 1
    @user3760188, If this answer helped you, please, mark it as a solution for this question – n0nvme Oct 12 '20 at 22:42
0

use Flask-Caching https://flask-caching.readthedocs.io/en/latest/

pip install Flask-Caching

Set Up

Cache is managed through a Cache instance:

from flask import Flask
from flask_caching import Cache

config = {
    "DEBUG": True,          # some Flask specific configs
    "CACHE_TYPE": "simple", # Flask-Caching related configs
    "CACHE_DEFAULT_TIMEOUT": 300
}
app = Flask(__name__)
# tell Flask to use the above defined config
app.config.from_mapping(config)
cache = Cache(app)

Caching View Functions

To cache view functions you will use the cached() decorator. This decorator will use request.path by default for the cache_key:

@app.route("/")
@cache.cached(timeout=50)
def index():
    return render_template('index.html')
Gregory R.
  • 1,815
  • 1
  • 20
  • 32