go - 如何使用 SingleFlight 共享下载的大文件?
问题描述
我正在代理一堆 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
要么
- 至少从自己的reponseWriter中看到结果
- 超时以及
r1
解决方案
https://github.com/golang/net/blob/master/http2/h2demo/h2demo.go#L181-L219 这行得通。原来我需要在 singleFlight.Group.Do 中返回处理程序而不是响应。我不知道为什么
推荐阅读
- node.js - lambda 在第一次运行时不更新 DynamoDB 数据,但在第二次运行时更新
- excel - VBA 格式编号无法识别
- java - 具有默认值的最小尺寸列表
- tsql - 来自 Parquet nvarchar 限制问题的 Azure Synapse Serverless External 表
- mysql - MySql过滤结果列表
- git - 如何检查存储库是否通过 HTTP 或 ssh 克隆?
- event-handling - svelte:如何在我自己的组件中使用事件修饰符
- android - 发布 KMM 库时未解决的对类型别名、内联函数和扩展函数的引用
- flutter - 如何用不同的捆绑ID从不同的产品风格调用同一家商店?[Flutter in_app_purchase]
- android - Android TV 应用程序设计:视频细节和视频水平列表