当DB不可访问时,Django AdminEmailHandler挂起

时间:2016-09-22 15:48:30

标签: python mysql django

我注意到当我的数据库关闭时,对我的Django应用程序的查询会给出超时,而不是立即向客户端返回500。

跟踪问题我将config中的数据库connect_timeout设置为5s(explained here)并且日志上的异常显得更快但是在打印异常后,客户端直到30多天才收到结果。

<center><span style="padding-bottom: 4px; display: inline-block;">


            <button onclick="buyside()">Swimming</button>
            <button onclick="sellside()">Gymnastics</button>
            <button onclick="clearFilters()">Clear Filters</button>

        </span></center>

调试PDB发生的事情我发现问题出现在 django.utils.log AdminEmailHandler 中,当它尝试生成异常邮件时。

要生成邮件,它会调用 django.views.debug ExceptionReporter.get_traceback_text(),它会查找回溯中的所有帧,然后查找每个帧上的所有变量,其中一个变量是触发异常的 queryset

生成错误电子邮件会对生成数据库连接超时的 queryset 进行多次访问,从而产生更多数据库超时,因此对客户端的错误响应需要很长时间。

避免此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

虽然没有给出更好的替代方案,但这是我实施的解决方案。

我已经设置了一个自定义的AdminEmailHandler来检查异常,并且在数据库的情况下,OperationalError会跳过异常并发送错误。

import logging

from django.utils.log import AdminEmailHandler
from django.db.utils import OperationalError

logger = logging.getLogger('mylogger')

class CustomAdminEmailHandler(AdminEmailHandler):

        # When mail is because of exception conencting to DB, avoid rendering the email,
        # rendering email makes connections to DB making the query hang in multiple DB 
        # connection timeouts.
        if record.exc_info:
            exc_type, exc_value, exc_traceback = record.exc_info
            if exc_type == OperationalError:
                logger.error(exc_value, exc_info=False)
                return

        super(CustomAdminEmailHandler, self).emit(record)

并在settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'simple': {
            'format': '%(asctime)s %(levelname)s %(module)s:%(funcName)s() %(message)s'
        },
    },
    'handlers': {
        'send_mail': {
            'level': 'ERROR',
            'class': 'myapp.handlers.CustomdAdminEmailHandler',
            'include_html': False,
        },
    },
    'loggers': {
        'django': {
            'handlers': ['send_mail'],
            'level': 'INFO'
        },
        'mylogger': {
            'handlers': ['send_mail'],
            'level': 'INFO'
        },
    }
}

我还将数据库连接超时设置为1秒,我不希望在数据库无法访问的情况下将请求排队,这可能会导致连接返回时负载非常高,可以获取服务器下来。