If you are using Flask to generate dynamic content of significant size, such as large binary images/pdf or large text-based datasets, then you need to consider streaming to minimize the memory footprint of Flask and preserve scalability.
Using an inner generate function and a yield allows Flask to return chunks of data back to the browser without the need to build an entire structure, image, or pdf in-memory.
@app.route('/large.csv') def generate_large_csv(): def generate(): for row in iter_all_rows(): yield ','.join(row) + '\n' return Response(generate(), mimetype='text/csv')
Prerequisites
You will need the Flask library installed to run this test.
sudo pip install Flask # If using Ubuntu16 sudo pip3 install Flask
Example Code
I have uploaded a sample Python Flask application to github, flask_stream_html.py. This sample application streams chunked html to the browser, allowing the end user to specify how many blocks of data to send and the number of bytes in each block.
# download entire project git clone https://github.com/fabianlee/python-flask-streamhtml.git cd python-flask-streamhtml # run streaming Flask app on port 8080 python3 ./flask-stream_html.py
Exposed URL
The application should now be running on port 8080, and you can pull down streaming content at the following URL:
# pull down streaming content http://localhost:8080/streamhtml # pull down 16kb http://localhost:8080/streamhtml?nblocks=16&block_size=1024 # pull down 256kb http://localhost:8080/streamhtml?nblocks=256&block_size=1024
You can access these URL with your local browser as well.
Client load testing
If you want to test the abilities of the server, try tweaking the parameters of the communication by changing the total size and chunk size under parallel load.
Apache Benchmark provides an easy way to perform basic load testing. First install the package:
sudo apt-get install apache2-utils
Then run a quick test of 10 total requests with 2 concurrent parallel requests. We set the parameters of the URL to return 16Kb total comprised of 16 chunks of 1024 bytes each.
ab -n 10 -c 2 http://localhost:8080/streamhtml?nblocks=16&block_size=1024
As another example, let’s return a larger scale test of 100 total requests with 10 concurrent. We set the parameters of the URL to return 50Kb comprised of 100 chunks of 512 bytes each.
ab -n 100 -c 10 http://localhost:8080/streamhtml?nblocks=100&block_size=512
REFERENCES
Flask docs, send_file_from_directory
Flask docs, streaming contents
stackoverflow, streaming content
github, CloudFoundry python-buildpack releases
github yuta-hono, cloudfoundry sample app for Flask. example manifest, runtime, Procfile
andrey zhukov, no-cache headers in flask
pythonize, flask before and after request functions
stackoverflow, flask stream with proxy and chunk_size
werkzeug, WSGI ClosingIterator and FileWrapper helpers