Flask应用程序中的asyncio event_loop



在Flask应用程序中运行异步事件循环的最佳方法是什么?

我的main.py看起来像这样:

if __name__ == '__main__':
try:
app.run(host='0.0.0.0', port=8000, debug=True)
except:
logging.critical('server: CRASHED: Got exception on main handler')
logging.critical(traceback.format_exc())
raise

为了添加异步任务的选项,我需要在运行app之前创建一个event_loop,但即使在停止应用程序运行时,后台线程仍然挂起(在调试器中可以观察到(

if __name__ == '__main__':
try:
app.event_loop = asyncio.get_event_loop()
app.run(host='0.0.0.0', port=8000, debug=True)
except:
logging.critical('server: CRASHED: Got exception on main handler')
logging.critical(traceback.format_exc())
raise
finally:
app.event_loop.stop()
app.event_loop.run_until_complete(app.event_loop.shutdown_asyncgens())
app.event_loop.close()

并使用以下内容创建异步任务:

def future_callback(fut):
if fut.exception():
logging.error(fut.exception())
def fire_and_forget(func, *args, **kwargs):
if callable(func):
future = app.event_loop.run_in_executor(None, func, *args, **kwargs)
future.add_done_callback(future_callback)
else:
raise TypeError('Task must be a callable')

我能找到的唯一解决方案是在finally块的末尾添加exit(),但我认为这不是正确的解决方案。

我最初对整个flask应用程序采用1 event_loop的方法,但由于一些不同的原因,我不喜欢这样。

相反,我创建了一个助手文件custom_flask_async.py,在中有两个函数

import asyncio

def get_set_event_loop():
try:
return asyncio.get_event_loop()
except RuntimeError as e:
if e.args[0].startswith('There is no current event loop'):
asyncio.set_event_loop(asyncio.new_event_loop())
return asyncio.get_event_loop()
raise e

def run_until_complete(tasks):
return get_set_event_loop().run_until_complete(asyncio.gather(*tasks))

如果要使用event_loop,我只检查它并get_set,并在特定请求中等待它。因为我使用它的主要方式是使用带有聚集的run_until_complete,所以我在助手中也有它。

我也不确定这是否是最好的方法,也不确定这种方法有什么缺点,但它绝对符合我的目的。

最终,我找到的最佳解决方案是在uwsgi中托管我的Flask应用程序,它可以使用mulesspooler执行异步任务

https://uwsgi-docs.readthedocs.io/en/latest/Spooler.html

https://uwsgi-docs.readthedocs.io/en/latest/Mules.html

相关内容

最新更新