';MySQL已经消失了';在Django项目外部使用Django ORM

';MySQL已经消失了';在Django项目外部使用Django ORM,mysql,django,Mysql,Django,我有一个Django应用程序和一个Tornado服务在同一台服务器上运行。在Tornado服务中,我使用Django ORM访问MySQL数据库。Django应用程序使用相同的数据库 Django web应用程序中的每个页面在客户端上呈现时,都会建立到Tornado服务的持久(WebSocket)连接。该服务使用Django ORM检索数据并将其返回给客户端 该网站使用率不高,有时几个小时甚至一两天可能会在后续请求之间消失 在Tornado网站闲置了一段时间后,我收到了Tornado服务中臭名昭

我有一个Django应用程序和一个Tornado服务在同一台服务器上运行。在Tornado服务中,我使用Django ORM访问MySQL数据库。Django应用程序使用相同的数据库

Django web应用程序中的每个页面在客户端上呈现时,都会建立到Tornado服务的持久(WebSocket)连接。该服务使用Django ORM检索数据并将其返回给客户端

该网站使用率不高,有时几个小时甚至一两天可能会在后续请求之间消失

在Tornado网站闲置了一段时间后,我收到了Tornado服务中臭名昭著的“2006:MySQL已经消失”错误。我做了一些挖掘,似乎罪魁祸首是MySQL断开的连接

然而,这就是让我困惑的地方:我使用的是Django应用程序使用的Django ORM,而Django应用程序本身却从未触发过这个错误。此外,我的理解是,如果发生此错误,Django ORM将自动重新连接,这解释了为什么我在Django应用程序中没有看到此错误。那么,为什么龙卷风会发生在我身上呢

现在,让Tornado实例恢复生命的唯一方法是重新启动运行它的gunicorn进程。重启后,龙卷风将不会打嗝,直到我离开它几个小时

我已经读过这篇文章:以及StackOverflow上类似问题的一些答案,但我认为增加MySQL上的超时并不能解决这个问题,它只是降低了发生的可能性。(无论如何,我的
wait\u timeout
被设置为一个相当大的值-
28800
。另一方面,为了避免这个问题,
max\u allowed\u packet
被设置为
16777216
,在这里不太可能是个问题,因为它失败的调用基本上只是从数据库检索会话对象)

Django核心开发人员之一在上面的链接中提出的另一个解决方案是显式关闭连接:
from Django.db import connection;connection.close()
当您知道您的程序将长时间处于空闲状态时。我实际上不知道这一点,因为我无法预测客户端请求页面的频率。在请求被送达后关闭连接对我来说也太过分了。如果没有其他方法,我当然会这么做,但这里似乎有什么不对劲,因为Django似乎应该透明地重新连接(我实际上在某个地方读过,但不完全确定这是真的)

我想我的主要问题是,如果需要关闭连接,为什么我的Django应用程序看起来就这么好?我不会关闭Django应用程序中的任何连接,但它不会引发相同的错误。如果关闭连接不是必需的并且是由Django自动完成的,那么为什么Tornado服务中使用的Django ORM会抛出这个错误呢

仅供参考,这是在Tornado应用程序中导致此错误的代码

def get_django_session(handler):
    if not hasattr(handler, '_session'):
        engine = importlib.import_module(
                django.conf.settings.SESSION_ENGINE)
        session_key = handler.get_cookie(django.conf.settings.SESSION_COOKIE_NAME)
        handler._session = engine.SessionStore(session_key)
    return handler._session


def get_current_user(handler):
    # get_user needs a django request object, but only looks at the session
    class Dummy(object):
        pass

    django_request = Dummy()
    django_request.session = get_django_session(handler)
    user = django.contrib.auth.get_user(django_request)  # 2006: MySQL has gone away
    if user.is_authenticated():
        return user
    else:
        return None

在每个请求之前和之后(通过
request\u启动
request\u完成
信号),Django调用,测试每个连接,如果连接不可用,则关闭连接。您可以在对连接执行任何操作之前和之后调用此方法。这不会关闭仍然可用的连接,因此您不会每次在Tornado中执行操作时都有新的连接。

谢谢。为了进一步扩展,这发生在(第65-66行)。此外,完整地说,Django确实透明地重新连接,如下所述:。您甚至可以显式地阻止Django这样做,除非经过CONN_MAX_AGE参数定义的特定时间间隔。