在Gunicorn超时中打印Django堆栈跟踪

7 投票
3 回答
3080 浏览
提问于 2025-04-17 19:16

我正在尝试调试一个Django应用程序偶尔出现的卡顿问题。目前我还没能找到具体原因,这个问题在生产环境中大约每天发生一次,而Gunicorn会重启这个进程,并显示一条信息:

[CRITICAL] WORKER TIMEOUT

有没有办法配置Django或Gunicorn,让它在重启进程时输出一个堆栈跟踪信息?

3 个回答

1

超时时间并不是用来限制请求的时间,而是用来检查工作进程是否还在正常运行。对于同步工作进程来说,这个超时时间就像请求的时间限制,因为同步工作进程只能处理请求,不能做其他事情。而异步工作进程在处理长时间运行的请求时,仍然会定期发送心跳信号,所以只要工作进程没有卡住或冻结,它就不会被杀掉。

Gunicorn 有一个叫做 worker_abort 的功能(下面有 Gunicorn 的文档链接)。

def worker_abort(worker):
    worker.log.info("worker received abort signal")
    import threading, sys, traceback
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId))
        stack = traceback.extract_stack(stack)
        for filename, lineno, name, line in stack:
            code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
            if line:
                code.append("  %s" % (line.strip()))
    worker.log.debug("\n".join(code))

这个功能在工作进程收到 SIGABRT 信号时被调用。通常情况下,这个调用是在超时发生时进行的。这个可调用对象需要接受一个实例变量,用于初始化工作进程。

来源:

http://docs.gunicorn.org/en/stable/settings.html, https://github.com/benoitc/gunicorn/issues/1493, https://github.com/benoitc/gunicorn/blob/master/examples/example_config.py

5

这段话的意思是,当工作进程被杀掉时,它会打印出一个堆栈跟踪信息。你需要创建一个 gunicorn 配置文件,然后把下面的函数粘贴到这个文件里。

import traceback
import io

def worker_abort(worker):
    debug_info = io.StringIO()
    debug_info.write("Traceback at time of timeout:\n")
    traceback.print_stack(file=debug_info)
    worker.log.critical(debug_info.getvalue())
6

试着把你的Gunicorn日志设置得更详细一些,可以把它调到INFO或者DEBUG,这样日志里可能会有更多有用的信息。

你也可以看看Dog Slow这个工具,它可以记录慢请求的情况。链接在这里:https://pypi.python.org/pypi/dogslow

还有一个通用的日志记录工具,叫Sentry,可以试试:https://www.getsentry.com/welcome/

顺便问一下,服务器上那时候有没有在运行的定时任务,比如备份之类的?

撰写回答