Как использовать SingleFlight для обмена загруженным файлом большого размера? - PullRequest
0 голосов
/ 05 апреля 2019

Я передаю кучу вызовов HTTP GET через singleflight.Но возвращенный ответ виден только по первому запросу.

Я также заметил проблему в моем тесте.Если первый запрос истечет, ответ будет потерян.

Допустим, r1,r2,r3 - это запросы, которые приходят в порядке.Все они сгруппированы в один groupKey.Если время ожидания r1 истекло, r2 и r3 будут ждать, пока общий HTTP-вызов не вернется, или пока не истечет их собственное время ожидания.

прокси-код (кредит здесь )

// add auth to the requst and proxy to target host
var serveReverseProxy = func(target string, res http.ResponseWriter, req *http.Request) {
    log.Println("new request!")
    requestURL, _ := url.Parse(target)
    proxy := httputil.NewSingleHostReverseProxy(requestURL)
    req1, _ := http.NewRequest(req.Method, req.RequestURI, req.Body)
    for k, v := range req.Header {
        for _, vv := range v {
            req1.Header.Add(k, vv)
        }
    }
    req1.Header.Set("Authorization", "Bearer "+"some token")
    req1.Host = requestURL.Host

    proxy.ServeHTTP(res, req1)
}

var requestGroup singleflight.Group
mockBackend := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
    groupKey := req.Host + req.RequestURI
    name := req.Header.Get("From")
    ch := requestGroup.DoChan(groupKey, func() (interface{}, error) {
        //increase key retention to 20s to make sure r1,r2,r3 are all in one group
        go func() {
            time.Sleep(20 * time.Second)
            requestGroup.Forget(groupKey)
            log.Println("Key deleted :", groupKey)
        }()

        // proxy to some host and expect the result to be written in res
        serveReverseProxy("https://somehost.com", res, req)
        return nil, nil
    })

    timeout := time.After(15 * time.Second)

    var result singleflight.Result
    select {
    case <-timeout: // Timeout elapsed, send a timeout message (504)
        log.Println(name, " timed out")
        http.Error(res, "request timed out", http.StatusGatewayTimeout)
        return
    case result = <-ch: // Received result from channel
    }

    if result.Err != nil {
        http.Error(res, result.Err.Error(), http.StatusInternalServerError)
        return
    }

    if result.Shared {
        log.Println(name, " is shared")
    } else {
        log.Println(name, " not shared")
    }
}))

Я бы ожидал, что r2, r3 либо

  1. по крайней мере увидят результат их собственного таймера reponseWriter
  2. вместе с r1

1 Ответ

0 голосов
/ 10 апреля 2019

https://github.com/golang/net/blob/master/http2/h2demo/h2demo.go#L181-L219 это работает. Оказывается, мне нужно возвращать обработчик в singleFlight.Group.Do вместо ответа. Я не знаю почему

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...