【Flask】AssertionError: Popped wrong app context.

发布时间 2023-05-31 11:16:04作者: binger0712

现象:

Traceback (most recent call last):
  File "src\\gevent\\greenlet.py", line 908, in gevent._gevent_cgreenlet.Greenlet.run
  File "************\venv\lib\site-packages\flask\ctx.py", line 157, in wrapper
    return f(*args, **kwargs)
  File "************\venv\lib\site-packages\flask\ctx.py", line 464, in __exit__
    self.auto_pop(exc_value)
  File "************\venv\lib\site-packages\flask\ctx.py", line 452, in auto_pop
    self.pop(exc)
  File "************\venv\lib\site-packages\flask\ctx.py", line 438, in pop
    app_ctx.pop(exc)
  File "************\venv\lib\site-packages\flask\ctx.py", line 241, in pop
    assert rv is self, "Popped wrong app context.  (%r instead of %r)" % (rv, self)
AssertionError: Popped wrong app context.  (<flask.ctx.AppContext object at 0x000001DD7CF510F0> instead of <flask.ctx.AppContext object at 0x000001DD7CFBA5C0>)
2023-05-31T02:26:16Z <Greenlet at 0x1dd7cf79048: handle_data(<Queue at 0x1dd7cf7de80>, sid_spaces={'ws': <geventwebsocket.websocket.WebSocket object)> failed with AssertionError
  • 在处理完毕相关事情,外部连接断开时,移除对栈中本次协程上下文
  • 不影响业务逻辑。

原因分析:

在一次请求事件中,使用gevent进行异步非阻塞任务,并使用copy_current_request_context进行request、g等上下文拷贝传递,结束时app上下文不存在,引发app栈移除失败
  • 使用时条件:flask、gevent、copy_current_request_context

解决办法:

  • 解决策略:在创建协程时,拷贝request的等上下文之前,应创建app上下文
  • 方案:
def copy_current_app_context(f):
    from flask.globals import _app_ctx_stack
    tx = _app_ctx_stack.top

    def wrapper(*args, **kwargs):
        with tx:
            return f(*args, **kwargs)

    return wrapper
copy_current_app_context 要在 request、g等拷贝前,即:copy_current_request_context