add_finished_callback() 中没有事务 - 如何重新启动?

No transaction in add_finished_callback() - how can it be restarted?

使用 Pyramid 框架和 SQLAlchemy 作为数据库后端。我正在尝试将一些长 运行 HTTP GET 请求推迟到视图上的 add_finished_callback() ,允许它在视图呈现后呈现并更新数据库。然而,交易似乎在 Pyramid 运行回调时关闭:

Traceback (most recent call last):
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\waitress-1.4.3-py3.8.egg\waitress\channel.py", line 349, in service
    task.service()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\waitress-1.4.3-py3.8.egg\waitress\task.py", line 169, in service
    self.execute()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\waitress-1.4.3-py3.8.egg\waitress\task.py", line 439, in execute
    app_iter = self.channel.server.application(environ, start_response)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\pyramid-1.10.4-py3.8.egg\pyramid\router.py", line 270, in __call__
    response = self.execution_policy(environ, self)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\pyramid_retry-2.1.1-py3.8.egg\pyramid_retry\__init__.py", line 127, in retry_policy
    response = router.invoke_request(request)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\pyramid-1.10.4-py3.8.egg\pyramid\router.py", line 260, in invoke_request
    request._process_finished_callbacks()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\pyramid-1.10.4-py3.8.egg\pyramid\request.py", line 138, in _process_finished_callbacks
    callback(self)
  File "C:\Users\kenne\PycharmProjects\FCMS\FCMS\views\callback.py", line 25, in test_callback
    print(f"Did some DB stuff, {ct.count()} and {cr.count()}")
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3749, in count
    return self.from_self(col).scalar()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3469, in scalar
    ret = self.one()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3436, in one
    ret = self.one_or_none()
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3405, in one_or_none
    ret = list(self)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3481, in __iter__
    return self._execute_and_instances(context)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3502, in _execute_and_instances
    conn = self._get_bind_args(
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3517, in _get_bind_args
    return fn(
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\query.py", line 3496, in _connection_from_session
    conn = self.session.connection(**kw)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\session.py", line 1138, in connection
    return self._connection_for_bind(
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\session.py", line 1146, in _connection_for_bind
    return self.transaction._connection_for_bind(
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\orm\session.py", line 458, in _connection_for_bind
    self.session.dispatch.after_begin(self.session, self, conn)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\sqlalchemy-1.3.17-py3.8-win-amd64.egg\sqlalchemy\event\attr.py", line 322, in __call__
    fn(*args, **kw)
  File "c:\users\kenne\pycharmprojects\fcms\venv\lib\site-packages\zope.sqlalchemy-1.3-py3.8.egg\zope\sqlalchemy\datamanager.py", line 268, in after_begin
    join_transaction(
  File "c:\users\kenne\pycharmprojects\fcms\venv\lib\site-packages\zope.sqlalchemy-1.3-py3.8.egg\zope\sqlalchemy\datamanager.py", line 233, in join_transaction
    DataManager(
  File "c:\users\kenne\pycharmprojects\fcms\venv\lib\site-packages\zope.sqlalchemy-1.3-py3.8.egg\zope\sqlalchemy\datamanager.py", line 89, in __init__
    transaction_manager.get().join(self)
  File "C:\Users\kenne\PycharmProjects\FCMS\venv\lib\site-packages\transaction-3.0.0-py3.8.egg\transaction\_manager.py", line 91, in get
    raise NoTransaction()
transaction.interfaces.NoTransaction

有谁知道在附加请求的 ZTM 中重新启动事务的好方法,还是应该使用在回调中实例化的单独数据库会话来完成?或者是否有理由在回调中根本不进行数据库处理?

add_finished_callback 运行s 在 tweens 之后,通常是清理发生的地方,并且是无序的,因此依赖数据库连接打开并不是一个好主意。

在请求的上下文中完成回调 运行 也毫无价值,因此您仍然在客户端执行时阻止将响应发送给客户端,因此将它们推迟到请求的后期实际上并没有给你带来太多好处。您必须将工作完全推迟到另一个线程才能更快地向客户端释放对 return 的响应,此时您肯定需要在该工作线程中打开一个新的数据库连接和事务。

如果您将 pyramid_tm 与您的数据库一起使用,则连接会在该补间的出口处关闭,之后访问 objects/database 通常会出现问题。