乐趣区

关于golang:聊聊dubbogoproxy的timeoutFilter

本文次要钻研一下 dubbo-go-proxy 的 timeoutFilter

timeoutFilter

dubbo-go-proxy/pkg/filter/timeout/timeout.go

func Init() {extension.SetFilterFunc(constant.TimeoutFilter, timeoutFilterFunc(0))
}

func timeoutFilterFunc(duration time.Duration) fc.FilterFunc {return New(duration).Do()}

// timeoutFilter is a filter for control request time out.
type timeoutFilter struct {
    // global timeout
    waitTime time.Duration
}

// New create timeout filter.
func New(t time.Duration) filter.Filter {
    if t <= 0 {t = constant.DefaultTimeout}
    return &timeoutFilter{waitTime: t,}
}

timeoutFilter 往 extension 设置了名为 `dgp.filters.timeout 的 timeoutFilterFunc,默认的 timeout 为 1s;timeoutFilterFunc 执行的是 timeoutFilter 的 Do 办法

Do

dubbo-go-proxy/pkg/filter/timeout/timeout.go

// Do execute timeoutFilter filter logic.
func (f timeoutFilter) Do() fc.FilterFunc {return func(c fc.Context) {hc := c.(*contexthttp.HttpContext)

        ctx, cancel := context.WithTimeout(hc.Ctx, f.getTimeout(hc.Timeout))
        defer cancel()
        // Channel capacity must be greater than 0.
        // Otherwise, if the parent coroutine quit due to timeout,
        // the child coroutine may never be able to quit.
        finishChan := make(chan struct{}, 1)
        go func() {
            // panic by recovery
            c.Next()
            finishChan <- struct{}{}
        }()

        select {
        // timeout do.
        case <-ctx.Done():
            logger.Warnf("api:%s request timeout", hc.GetAPI().URLPattern)
            bt, _ := json.Marshal(filter.ErrResponse{Message: http.ErrHandlerTimeout.Error()})
            hc.SourceResp = bt
            hc.TargetResp = &client.Response{Data: bt}
            hc.WriteJSONWithStatus(http.StatusGatewayTimeout, bt)
            c.Abort()
        case <-finishChan:
            // finish call do something.
        }
    }
}

func (f timeoutFilter) getTimeout(t time.Duration) time.Duration {
    if t <= 0 {return f.waitTime}

    return t
}

Do 办法会通过 context.WithTimeout 创立 ctx 及 cancel,而后注册 defer 这个 cancel func;之后创立 finishChan,异步执行 c.Next(),之后往 finishChan 写入数据;最初 select 判断 ctx.Done() 或者是 finishChan;如果是 ctx.Done() 则示意 timeout 了,返回 http.StatusGatewayTimeout

小结

dubbo-go-proxy 的 timeoutFilter 默认设置了 1s 超时,它通过 context.WithTimeout 创立 ctx 及 cancel,并异步执行 c.Next(),若 ctx.Done() 则示意 timeout 了,返回 http.StatusGatewayTimeout;若是读取到了 finishChan 则示意申请失常响应。

doc

  • dubbo-go-proxy
退出移动版