我正在将现有的python GAE(谷歌应用引擎)标准环境应用程序迁移到灵活的环境中。我通读了指南,决定试用python compact运行时,因为尽可能多地重用代码总是很好的。
在标准环境应用程序中,我们使用background_thread.start_new_background_thread()生成一堆无限循环线程,以便永远处理一些后台工作。然而,我无法让start_new_background_thread在灵活的环境中工作,即使对于一些非常简单的应用程序也是如此。喜欢此示例应用程序:github.com/GoogleCloudPlatform/python-docs-samples/tree/master/appengine/background
在云中运行该应用程序时,我不断收到以下错误(不过它在本地运行良好)。
我使用云调试器对其进行了调试,但在background_thread.py 中引发异常时,根本没有任何错误消息
知道我如何在具有python紧凑运行时的灵活环境中运行长寿命后台线程吗?谢谢
应用程序引擎标准和应用程序引擎灵活性之间的区别之一是,使用Flex,我们实际上只是在运行一个docker容器。我能想出两种方法来尝试。
1.只需使用Python多处理
应用程序引擎标准强制执行沙盒,这主要意味着不直接使用线程或进程。使用Flex,您应该能够使用标准Python库来启动新的子进程:
https://docs.python.org/3/library/subprocess.html
2.使用监督员和码头工人
如果这不起作用,您可以在这里采取的另一种方法是自定义您在Flex中使用的docker映像,并使用supervisord启动多个进程。首先,通过将源代码刻录到文件夹中并运行来生成dockerfile
gcloud preview app gen-config --custom
这将创建一个可以自定义的Dockerfile。现在,您将想要启动2个进程-我们正在启动的进程(我认为对于python-compat,它是gunicorn)和您的后台进程。使用docker最简单的方法是使用supervisord:
https://docs.docker.com/engine/admin/using_supervisord/
在修改Dockerfile并添加supervisord.conf后,您可以像使用gcloud preview app deploy
一样部署应用程序。
希望这能有所帮助!
我希望文档中说明background_thread
不是支持的API。
无论如何,我找到了一些技巧来帮助解决一些线程不兼容的问题。App Engine使用os.environ
读取大量设置。应用程序中的"真实"线程将在那里设置一组环境变量。您启动的后台线程将没有。我用过的一种方法是复制一些环境变量。例如,我需要在后台线程中复制并设置SERVER_SOFTWARE
变量,以便让AppEngine云存储库正常工作。我们使用类似的东西:
_global_server_software = None
_SERVER_SOFTWARE = 'SERVER_SOFTWARE'
def environ_wrapper(function, args):
if _global_server_software is not None:
os.environ[_SERVER_SOFTWARE] = _global_server_software
function(*args)
def start_thread_with_app_engine_environ(function, *args):
# HACK: Required for the cloudstorage API on Flexible environment threads to work
# App Engine relies on a lot of environment variables to work correctly. New threads get none
# of those variables. loudstorage uses SERVER_SOFTWARE to determine if it is a test instance
global _global_server_software
if _global_server_software is None and os.environ.get(_SERVER_SOFTWARE) is not None:
_global_server_software = os.environ[_SERVER_SOFTWARE]
t = threading.Thread(target=environ_wrapper, args=(
function, args))
t.start()