title: How to use SingleFlight to share downloaded large size file?
body: <p>I'm proxying a bunch of http GET calls through <code>singleflight</code>. But returned response is only seen by the first request. </p>
  
  <p>I also noticed a problem in my test. If the first request times out, the response will be lost.</p>
  
  <p>Let's say <code>r1,r2,r3</code> are requests that come in order. They are all grouped in one <code>groupKey</code>. If <code>r1</code> time out , <code>r2</code> and <code>r3</code> will wait until the shared HTTP call returns or until their own timeout.</p>
  
  <p>proxy code (credits to <a href="https://medium.com/@vCabbage/go-avoid-duplicate-requests-with-sync-singleflight-311601b3068b" rel="nofollow noreferrer">here</a>)</p>
  
  <pre class="lang-golang prettyprint-override"><code>// 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 &lt;-timeout: // Timeout elapsed, send a timeout message (504)
          log.Println(name, " timed out")
          http.Error(res, "request timed out", http.StatusGatewayTimeout)
          return
      case result = &lt;-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")
      }
  }))
  </code></pre>
  
  <p>I'd expect <code>r2</code>,<code>r3</code> to either</p>
  
  <ol>
  <li>at least see the result from their own reponseWriter</li>
  <li>timeout along with <code>r1</code></li>
  </ol>