Flask 应用程序中的 asyncio event_loop
asyncio event_loop in a Flask app
在 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
,其中包含 2 个函数,
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))
我只检查 get_set
event_loop 是否要使用,并在特定请求中等待。因为我使用它的主要方式是使用带有收集的 run_until_complete
,所以我也在帮助程序中使用了它。
我也不确定这是否是最好的方法,或者这种方法有什么缺点,但它绝对适合我的目的。
最终我找到的最佳解决方案是在 uwsgi
中托管我的 Flask 应用程序,这样可以使用 mules
和 spooler
进行异步任务
在 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
,其中包含 2 个函数,
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))
我只检查 get_set
event_loop 是否要使用,并在特定请求中等待。因为我使用它的主要方式是使用带有收集的 run_until_complete
,所以我也在帮助程序中使用了它。
我也不确定这是否是最好的方法,或者这种方法有什么缺点,但它绝对适合我的目的。
最终我找到的最佳解决方案是在 uwsgi
中托管我的 Flask 应用程序,这样可以使用 mules
和 spooler
进行异步任务