mysql - 在 Django 项目之外使用 Django ORM,“MySQL 已经消失”

标签 mysql django

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

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

该网站使用不频繁,有时后续请求之间可能会间隔几个小时甚至一两天。

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

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

就目前而言,让我的 Tornado 实例恢复生机的唯一方法是重新启动运行它的 gunicorn 进程。重新启动后,Tornado 将正常工作,直到我让它保持几个小时。

我读过这个:https://code.djangoproject.com/ticket/21597#comment:29以及 StackOverflow 上类似问题的一些答案,但我不认为增加 MySQL 的超时可以解决问题,它只会降低它发生的可能性。 (无论如何,我的 wait_timeout 设置为一个相当大的值 - 28800。另一方面,为了让它不碍事,max_allowed_pa​​cket code> 设置为 16777216 并且在这里不太可能成为问题,因为它失败的调用基本上只是从数据库中检索 session 对象。)

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_startedrequest_finished 信号),Django 调用 close_old_connections() ,它会测试每个连接并在无法使用时将其关闭。您可以在对连接进行任何操作之前和之后调用此方法。这不会关闭仍然可用的连接,因此您每次在 Tornado 中执行某些操作时不会有新连接。

关于mysql - 在 Django 项目之外使用 Django ORM,“MySQL 已经消失”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38041522/

相关文章:

php - 全文搜索 MySQL

MySql 自动递增停在 255

mysql - 在django中采样mysql结果

python - 创建一个函数来为上传的图像位置指定目录

php - json 列与多列

php - MYSQL Max(column) 其中 2 个表具有相同的列

django - 如何在 django 中获取上次登录 ip 并保存到 GenericIPAddressField?

python - TypeError : int() argument must be a string, 类似字节的对象或数字,而不是 'list'

html - 弄清楚为什么 django 现在找不到我的模板的脚本、样式表和插件

mysql - 为什么我不能用 'goapp deploy' 部署到 GAE,我找不到导入 : "github.com/go-sql-driver/mysql"