fix(proxy): prevent use-after-recycle in background cache refresh
Copy the request before spawning the background goroutine. The fasthttp.RequestCtx is recycled after the handler returns, so passing it to a goroutine causes data corruption under high concurrency. The caller now AcquireRequest+CopyTo before go(), and the goroutine releases it. backgroundRefresh no longer accepts ctx directly.
This commit is contained in:
parent
c2dd4fa9a3
commit
2c3cc1ba38
@ -55,20 +55,14 @@ func (p *Proxy) writeCachedResponse(ctx *fasthttp.RequestCtx, entry *cache.Proxy
|
||||
// 该方法在独立 goroutine 中运行,不阻塞主请求流程。
|
||||
//
|
||||
// 参数:
|
||||
// - ctx: 原始 FastHTTP 请求上下文(仅用于复制请求信息)
|
||||
// - req: 预复制的请求副本(调用方负责 Acquire/Release)
|
||||
// - target: 要刷新的后端目标
|
||||
// - hashKey: 缓存哈希键
|
||||
// - origKey: 缓存原始键
|
||||
func (p *Proxy) backgroundRefresh(ctx *fasthttp.RequestCtx, target *loadbalance.Target, hashKey uint64, origKey string) {
|
||||
// 创建新的请求上下文副本
|
||||
req := fasthttp.AcquireRequest()
|
||||
func (p *Proxy) backgroundRefresh(req *fasthttp.Request, target *loadbalance.Target, hashKey uint64, origKey string) {
|
||||
resp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseRequest(req)
|
||||
defer fasthttp.ReleaseResponse(resp)
|
||||
|
||||
// 复制原始请求
|
||||
ctx.Request.CopyTo(req)
|
||||
|
||||
// 如果启用 Revalidate,添加条件请求头
|
||||
if p.config.Cache.Revalidate {
|
||||
if entry, ok, _ := p.cache.Get(hashKey, origKey); ok {
|
||||
|
||||
@ -651,14 +651,17 @@ func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) {
|
||||
}
|
||||
return
|
||||
}
|
||||
// 过期缓存,尝试后台刷新,同时返回旧数据
|
||||
if !p.config.Cache.BackgroundUpdateDisable {
|
||||
entry.Updating.Store(true)
|
||||
go func() {
|
||||
defer entry.Updating.Store(false)
|
||||
p.backgroundRefresh(ctx, target, hashKey, origKey)
|
||||
}()
|
||||
}
|
||||
// 过期缓存,尝试后台刷新,同时返回旧数据
|
||||
if !p.config.Cache.BackgroundUpdateDisable {
|
||||
entry.Updating.Store(true)
|
||||
reqCopy := fasthttp.AcquireRequest()
|
||||
ctx.Request.CopyTo(reqCopy)
|
||||
go func() {
|
||||
defer entry.Updating.Store(false)
|
||||
defer fasthttp.ReleaseRequest(reqCopy)
|
||||
p.backgroundRefresh(reqCopy, target, hashKey, origKey)
|
||||
}()
|
||||
}
|
||||
upstreamAddr = upstreamCache
|
||||
upstreamStatus = entry.Status
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user