gevent和posgres:异步连接失败

ado*_*lis 5 python django postgresql gevent

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

我用猴子修补了:

import gevent.monkey; gevent.monkey.patch_socket()
Run Code Online (Sandbox Code Playgroud)

我使用以下方法修补了psychopg:

import psycogreen; psycogreen.gevent.patch_psycopg()
Run Code Online (Sandbox Code Playgroud)

尽管如此,某些Django调用因此Model.save()失败并出现错误:"异步连接失败".我是否需要做其他事情才能在Django环境中制作postgres greenlet-safe?还有什么我想念的吗?

Mar*_*rat 5

一篇关于这个问题的文章,不幸的是它是用俄语写的.让我引用最后一部分:

所有连接都存储在django.db.connections中,这是django.db.utils.ConnectionHandler的实例.每次ORM即将发出查询时,它都会通过调用连接['default']来请求数据库连接 .反过来,ConnectionHandler .__ getattr__检查ConnectionHandler._connections中是否存在 连接,如果它为空则创建一个新连接.

所有打开的连接应在使用后关闭.有一个信号 request_finished,由django.http.HttpResponseBase.close运行 .Django在最后一刻关闭数据库连接,当时没有人可以再使用它 - 这似乎是合理的.

然而,关于ConnectionHandler如何存储数据库连接存在棘手的部分.它使用threading.local,在monkeypatching之后变成 gevent.local.local.声明一次,这个结构就像它在每个greenlet中都是唯一的一样.Controller*some_view*在一个greenlet中开始工作,现在我们在*ConnectionHandler._connections*中有一个连接.然后我们创建了更多的greenlets,它们得到一个空的*ConnectionHandlers._connections*,并且他们从池中获得了connectinos.在完成新的greenlet之后,他们的local()的内容消失了,并且数据库连接也没有返回池中.在某个时刻,游泳池变空了

开发Django + gevent你应该始终牢记这一点并通过调用django.db.close_connection来关闭数据库连接.它应该在异常时调用,你可以使用装饰器,如:

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
Run Code Online (Sandbox Code Playgroud)