使用Django项目之外的Django ORM,“MySQL已经消失了”

时间:2016-06-26 18:02:24

标签: mysql django

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

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

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

在网站闲置一段时间之后,我在Tornado服务中得到臭名昭着的'2006:MySQL已经消失'错误。我做了一些挖掘,看起来罪魁祸首是MySQL正在删除连接。

然而,令我感到困惑的是:我使用的是与Django应用程序使用的相同的Django ORM,但Django应用程序本身从未触发此错误。此外,我的理解是,如果发生此错误,Django ORM会自动重新连接,这就解释了为什么我在Django应用程序中没有看到此错误。为什么在龙卷风中我会发生这种情况呢?

现在看来,让我的Tornado实例恢复生机的唯一方法就是重新启动运行它的gunicorn进程。重新启动后,Tornado将毫无打嗝地工作,直到我离开几个小时。

我已经读过这个:https://code.djangoproject.com/ticket/21597#comment:29以及StackOverflow上类似问题的一些答案,但我不认为增加MySQL的超时解决了这个问题,它只是让它不太可能发生。 (无论如何,我的wait_timeout设置为一个相当大的值 - 28800。另一方面,为了让它不受影响,max_allowed_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

1 个答案:

答案 0 :(得分:3)

在每个请求之前和之后(通过[HttpPost] public JsonResult PostQuestionAndOptions(MyValues model) { return Json(true, JsonRequestBehavior.AllowGet); } request_started信号),Django调用close_old_connections(),它测试每个连接并在它无法使用时关闭它。您可以在对连接执行任何操作之前和之后调用此方法。这不会关闭仍然可用的连接,因此每次在Tornado中执行某些操作时都不会有新的连接。