Search code examples
pythongoogle-app-engineflaskgcloud

Problem running Flask App on Google Cloud App Engine


So I have a simple Flask app (no database connected) that needs to execute a function with arguments parsed via a form. This function processes large amounts of data (and takes a few minutes to do so), and it's divided in parts, after which, yields some strings. The idea is that while the function is running, these strings appear dinamically on a template. And I was able to make that, and when the app is hosted on a local server it functions correctly. But, when deployed to Google Cloud App Engine, it does not allow me to dinnamically output theses strings, instead, it waits till all the function was executed to output them. main.py

from flask import Flask, render_template, redirect, url_for, request, session, flash, Response
import requests
from jinja2 import Environment
from jinja2.loaders import FileSystemLoader

app = Flask(__name__)
app.secret_key = "123"

def my_function(arg1, arg2, arg3):
   #Does something and defines string1
   yield string1
   #Does something else and defines string2
   yield string2
   #Does something else and defines string3
   yield string3

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':
       arg1 = request.form.get('arg1')
       arg2 = request.form.get('arg2')
       arg3 = request.form.get('arg3')

       env = Environment(loader=FileSystemLoader('templates'))
       tmpl = env.get_template('result.html')
       return Response(tmpl.generate(result = my_function(arg1, arg2, arg3)))

   return render_template("index.html")

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

index.html

<form method="POST">
   <input type="text" name="arg1">
   <input type="text" name="arg2">
   <input type="text" name="arg3">
   <input type="submit">
</form>

result.html

<div>
    {% for line in result %}
       <p>{{ line }}</p>
    {% endfor %}
</div>

app.yaml

runtime: python37

Terminal output after running $ python main.py and submitting form

"GET / HTTP/1.1" 200
"POST / HTTP/1.1" 200

and opens result.html while my_function() is running

Terminal output after deploying and running $ gcloud app logs read

https://i.sstatic.net/6lBIt.png

and stays on index.html till my_function() ends running and then opens result.html


Solution

  • As @DazWilkin said - App Engine does not support streaming. In addition, App Engine has a deadline of 1 minute for each request i.e. each call to App Engine as part of your standard app has to return within a minute

    With respect to your issue, you can

    1. Make an ajax call to a route on your end which kicks off a function (running on a different thread). This function runs and dumps output in a list
    2. Your Ajax call then initiates a polling routine i.e. every X seconds, make a call to the function in #1 above and return any values in the output bucket

    It solves your problem but the results are not instantaneous - they are dependent on how often you poll your server.

    If you really need real-time response and your application is significant or large then you'll have to look into PubSub but this won't run on app engine (as earlier mentioned). You'll have to go the route of Google Compute Engine (GCE)