1

我使用 Cherrypy 在 Python 3.2 之上构建了一个小的自定义 Web 框架来构建 WSGI 应用程序和 SQLAlchemy Core(仅用于连接池和执行文本 SQL 语句)。

我正在使用的版本:

  • 蟒蛇:3.2.3
  • 樱桃派:3.2.2
  • SQL 炼金术:0.7.5
  • Psycopg2:2.4.5

对于每个请求,使用sqlalchemy.engine.base.Engine´sconnect方法从池中检索数据库连接。请求处理程序完成后,使用close方法关闭连接。伪代码例如:

with db.connect() as db:
    handler(db)

上下文管理器在哪里db.connect() 定义如下:

@contextmanager
def connect(self):
    conn = self.engine.connect()
    try: 
        yield conn
    finally:
        conn.close()

我希望这是完成这项任务的正确做法。它一直有效,直到页面处理程序中的事情变得更加复杂。

我的行为很奇怪。由于未知原因,连接有时会在处理程序完成工作之前关闭。但不是每次!

通过观察,这仅在连续快速发出请求时才会发生。如果我在请求之间稍作停顿,则连接不会关闭并且请求成功完成。但无论如何,这种情况并非每次都会发生。我没有在请求的失败/成功中找到更具体的模式。

我观察到我的上下文管理器没有关闭连接。那时它已经关闭了。

我的问题: 如何确定我的连接何时、为什么以及通过什么代码关闭?

我尝试调试。我在sqlalchemy.engine.base.Connection´sclose方法上设置了断点,但连接在到达此代码之前已关闭。这很奇怪。

我将不胜感激任何提示或帮助。

*编辑 * zzzeek 要求的信息:

“连接被关闭”的症状:很抱歉之前没有澄清这一点。它sqlalchemy.engine.Connection是封闭的。

在处理程序中,我调用sqlalchemy.engine.base.Connection´sexecute方法从数据库中获取数据(选择语句)。我可以说它sqlalchemy.engine.Connection是关闭的,因为我closed在调用执行之前检查它的属性。

我可以在此处发布回溯,但您可能会在其中看到的唯一一件事是在我的 DB 包装器库中执行之前引发了异常(因为连接已关闭)。

如果我删除此检查(并让execute方法执行),SQLAlchemy 会引发此异常: http: //pastebin.com/H6052yca

关于 zzzeek 提到的并发问题。我必须道歉。经过更多观察,情况略有不同。

这是如何调用错误的确切过程:

Request for HandlerA. Everything ok. 
Wait moment (about 10-20s).
Request for HandlerB. Everything ok.

Request for HandlerA. Everything ok.
Immediate request for HandlerB. Error!
Immediate request for HandlerB. Error!
Immediate request for HandlerB. Error!
Wait moment (about 10-20s).
Request for HandlerB. Everything ok.

我正在使用 pool_size = 5 的默认 SQLAlchemy 池类。

我知道当你没有实际代码时,你无法创造奇迹。但不幸的是,我不能分享它。是否有调试此类错误的最佳实践?还是唯一的选择是一步一步地更深入地调试并尝试弄清楚?

另一个观察:

当我在调试器(WingIDE)中启动服务器时,我无法显示错误。可能是因为调试器在解释代码时太慢了,以至于在处理第二个请求(RequestB)之前,连接以某种方式“修复”了。

4

1 回答 1

4

经过一天的调试。我发现了问题。

不幸的是,它与 SQLAlchemy 没有直接关系。所以这个问题应该被删除。但是你们试图帮助我,所以我会回答我自己的问题。也许有一天,有人会发现这很有帮助。

基本上,错误是由我的自定义发布/订阅方法引起的,这些方法在多线程环境中表现不佳。

我尝试逐行步进代码......这是行不通的(正如我在问题中描述的那样)。所以我开始生成非常详细的日志记录正在发生的事情。

即便如此,一切看起来都很正常,直到我注意到崩溃前的几行,模型中引用的 Connection 对象的地址发生了变化。这实际上意味着将另一个 Connection 对象分配给模型,并且该连接对象已经关闭。

所以教训是。当一切看起来正确时,打印/记录有问题的对象的 repr()。

感谢评论者的时间。

于 2012-08-27T16:27:30.873 回答