提问人:msfrn 提问时间:9/18/2023 更新时间:9/19/2023 访问量:71
在 Google Cloud 上部署时,flask 应用中的回调不起作用
Callbacks in flask app don't work when deployed on Google Cloud
问:
我有一个 Flask 应用程序,它使用输入表单(GET 方法)来运行一些随机模拟。仿真结果存储在 flask App 中的全局变量中,然后显示一些初始绘图。然后,用户可以自由地回调模拟的其他部分(存储在全局变量中),并使用回调显示其他图形。
有关代码,请参阅此处:github-repo
对于涉及较少代码的类似但最小的概念:其他 github-repo(将一些随机值存储在全局变量中,用于提取和显示这些值的回调,不涉及绘图)
这两个应用程序都使用 flask 的开发服务器在我的本地机器上按预期工作。但是,当部署到 Google Cloud(App Engine 标准环境)时,回调虽然一开始可以工作,但最终会停止工作。每当触发回调时,日志都会返回“TypeError: 'NoneType' object is not subscriptable”(我猜这意味着保存数据的全局变量丢失了)。
可能无关紧要,但几秒钟后,图形应用程序将再次开始工作,而无需重新提交表单/重新加载页面,但很明显,模拟是从头开始重新运行的,原始结果丢失了。然后,它开始进入停止和重新开始的循环,并进行新的模拟。另一方面,最小的应用程序完全停止工作,仅此而已。
作为一个完全的新手,我怀疑这与服务器端请求超时有关,但我注意到应用程序在一个看似随机的时间点停止工作。它可以在加载页面后立即进行,也可以继续工作一分钟。如果是请求超时问题,我想我会看到一些一致性(例如,在最后一个请求后 30 秒始终停止工作)。我试图调查谷歌云文档,但是(作为一个完全的新手),我试图自己解决这个问题,无法弄清楚导致这种行为的服务器问题是什么,以及我该如何解决它(假设这是一个服务器端问题)。任何帮助或指点将不胜感激,谢谢。
答:
使用精简示例中的代码
GAE 创建实例(意味着可以是多个)来满足/处理流量。
想象一下,当您加载主页时,它会创建一个实例。加载主页会初始化全局变量。
当用户选择名称时,将对回调发出 GET 请求,该回调会根据全局变量返回一个值。您不断选择不同的名称,并且每次都会触发回调。
但是,选择触发对回调的 GET 调用的其他名称可能会导致创建一个新实例(以处理流量)。该新实例意味着您的代码将重新(全新)加载到该实例中,这意味着该实例的全局变量为 None。然后,此新实例调用回调的代码。全局变量永远不会初始化,因为根本没有调用主页的代码。
问题的可能解决方案是将以下内容添加到文件中app.yaml
automatic_scaling:
max_instances: 1
这意味着您告诉 GAE 无论流量如何,都只创建 1 个应用程序实例。这样做可以消除前面步骤中发现的问题。不过,这样做的缺点是,随着流量的增加,某些人会遇到瓶颈和可能的超时。
另一种可能的解决方案是在任何函数之外初始化全局变量,即将其紧跟在 之后。这将消除当前错误,但您仍然可能会收到其他错误,其中更新的全局变量不可用(因为已创建新实例并且全局变量返回到初始化值)。app = Flask(__name__)
"TypeError: 'NoneType' object is not subscriptable"
上述两个更好的选择是将值存储在 memcache 中,然后在每次调用回调时从 memcache 读取,或者将值传递给客户端并让客户端在调用回调时发回值
评论