You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gunicorn与Django:请求超时自定义错误抛出方案咨询

Django层面主动捕获请求超时并抛出自定义TimeoutError的最优方案

核心思路

在Django请求处理流程中,设置一个略短于Gunicorn超时时间的请求超时阈值(比如Gunicorn设20秒,Django设18秒),当请求处理耗时达到该阈值时,主动抛出自定义TimeoutError,确保监控工具(Datadog/Sentry)能完整捕获错误上下文,避免Gunicorn发送SigAbt杀死进程导致的追踪中断。

实现方案:自定义Django中间件

中间件是Django中拦截所有请求的最佳入口,通过系统信号实现超时触发,无需额外依赖:

1. 定义自定义超时异常

在项目的exceptions.py中添加:

class TimeoutError(Exception):
    """自定义请求超时异常"""
    pass

2. 编写超时处理中间件

在项目的middleware.py中实现中间件:

import signal
from django.http import JsonResponse
from .exceptions import TimeoutError

class RequestTimeoutMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 设置超时时间(比Gunicorn的timeout小2秒,避免冲突)
        self.timeout_seconds = 18

    def __call__(self, request):
        # 定义超时信号处理函数
        def handle_timeout(signum, frame):
            raise TimeoutError("请求处理超时,已主动终止")

        # 注册SIGALRM信号及处理函数
        signal.signal(signal.SIGALRM, handle_timeout)
        # 设置超时闹钟
        signal.alarm(self.timeout_seconds)

        try:
            response = self.get_response(request)
        except TimeoutError as e:
            # 捕获自定义超时异常,返回标准错误响应
            response = JsonResponse({"error": str(e)}, status=504)
            # 触发Sentry/Datadog的错误上报(如果已集成)
            raise e
        finally:
            # 请求处理完成,取消闹钟
            signal.alarm(0)

        return response

3. 激活中间件

在settings.py的MIDDLEWARE列表中添加该中间件(建议放在靠前位置,确保所有请求都被拦截):

MIDDLEWARE = [
    'your_project.middleware.RequestTimeoutMiddleware',
    # 其他中间件...
    'django.middleware.common.CommonMiddleware',
    # ...
]

4. 调整Gunicorn配置

确保Gunicorn的--timeout值大于Django中间件设置的超时时间,保持原配置即可:

gunicorn config.wsgi --timeout 20 (...)

关键注意事项

  • 信号兼容性:SIGALRM仅在类Unix系统(如Linux)中可用,符合EKS集群的运行环境。
  • 多进程安全:Gunicorn的每个worker是独立进程,信号注册仅作用于当前worker进程,不会跨进程干扰。
  • 异常上报:捕获TimeoutError后重新抛出,确保已集成的监控工具能正常捕获并记录错误堆栈。
  • 边缘场景处理:在finally块中取消闹钟,避免请求正常完成后仍触发超时信号。

可选优化方案

如果需要更精细的超时控制(比如针对特定视图设置不同超时),可以扩展中间件,通过视图装饰器传递自定义超时值:

# 视图装饰器
def timeout(seconds):
    def decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            request.timeout_seconds = seconds
            return view_func(request, *args, **kwargs)
        return _wrapped_view
    return decorator

# 修改中间件的__call__方法,优先使用视图设置的超时
def __call__(self, request):
    timeout_seconds = getattr(request, 'timeout_seconds', self.timeout_seconds)
    # ... 后续超时逻辑保持不变

内容的提问来源于stack exchange,提问作者Yassine Belmamoun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:45:07