gevent和postgres:异步连接失败

5

我正在使用gevent来处理基于Django的Web系统上的API I/O。

我已经使用了monkey-patch:

import gevent.monkey; gevent.monkey.patch_socket()

我使用以下方式对psychopg进行了打补丁操作:
import psycogreen; psycogreen.gevent.patch_psycopg()

然而,某些Django调用(如Model.save())会出现错误:"异步连接失败"。在Django环境中,我需要做些其他事情来使postgres greenlet安全吗?还有其他我漏掉的东西吗?

1个回答

7

这篇文章讲述了这个问题,但不幸的是它是用俄语写的。让我引用最后一部分:

所有的连接都存储在django.db.connections中,这是一个django.db.utils.ConnectionHandler实例。每次ORM准备发出查询时,它通过调用connections['default']来请求一个DB连接。然后,ConnectionHandler.__getattr__检查ConnectionHandler._connections中是否有连接,如果为空则创建新连接。

所有打开的连接在使用完后都应该关闭。有一个信号request_finished,由django.http.HttpResponseBase.close运行。Django在最后一刻关闭DB连接,当没有人再使用它时,这似乎是合理的。

但是关于ConnectionHandler如何存储DB连接有一个棘手的问题。它使用threading.local,在猴子补丁后变成gevent.local.local。声明一次后,该结构就像在每个greenlet上都是唯一的一样工作。控制器*some_view*在一个greenlet中开始工作,现在我们在*ConnectionHandler._connections*中获得了一个连接。然后我们创建了几个更多的greenlets,并从池中获取空的*ConnectionHandlers._connections*,它们从池中获取连接。新greenlets完成后,它们的local()的内容消失了,DB连接也随之消失,而未被返回到池中。在某个时刻,池会变空。

开发Django+gevent时,您应该始终记住这一点,并通过调用django.db.close_connection来关闭DB连接。在异常时也应该调用它,可以使用装饰器,例如:

class autoclose(object):
    def __init__(self, f=None):
        self.f = f

    def __call__(self, *args, **kwargs):
        with self:
            return self.f(*args, **kwargs)

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_info, tb):
        from django.db import close_connection
        close_connection()
        return exc_type is None

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接