diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 2899a94..fc25a5e 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -409,6 +409,8 @@ func GenerateConfigYAML(cfg *Config) ([]byte, error) { buf.WriteString(" # cache_lock: true # 防止缓存击穿\n") buf.WriteString(" # cache_lock_timeout: 5s # 缓存锁超时时间(默认 5s)\n") buf.WriteString(" # stale_while_revalidate: 30s\n") + buf.WriteString(" # stale_if_error: 1m # 上游错误时使用过期缓存的时间窗口\n") + buf.WriteString(" # stale_if_timeout: 30s # 上游超时时使用过期缓存的时间窗口\n") buf.WriteString(" # background_update_disable: false # 禁用后台更新(默认启用)\n") buf.WriteString(" # cache_ignore_headers: [] # 缓存时忽略的响应头\n") buf.WriteString(" # revalidate: false # 启用条件请求(默认关闭)\n") diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index b172f09..06eefc8 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -181,7 +181,7 @@ func NewProxy(cfg *config.ProxyConfig, targets []*loadbalance.Target, transportC MaxAge: cfg.Cache.MaxAge, }) } - p.cache = cache.NewProxyCache(rules, cfg.Cache.CacheLock, cfg.Cache.StaleWhileRevalidate) + p.cache = cache.NewProxyCache(rules, cfg.Cache.CacheLock, cfg.Cache.StaleWhileRevalidate, cfg.Cache.StaleIfError, cfg.Cache.StaleIfTimeout) } // 初始化重定向改写器 @@ -683,6 +683,19 @@ func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) { p.healthChecker.MarkUnhealthy(target) } + // 尝试使用 stale 缓存 + if p.cache != nil { + hashKey, origKey := p.buildCacheKeyHash(ctx) + isTimeout := errors.Is(err, fasthttp.ErrTimeout) + if staleEntry, ok := p.cache.GetStale(hashKey, origKey, isTimeout); ok { + logging.Info().Msgf("[PROXY] 使用 stale 缓存: key=%s, isTimeout=%v", origKey, isTimeout) + p.writeCachedResponse(ctx, staleEntry) + upstreamStatus = staleEntry.Status + upstreamAddr = upstreamCache + return + } + } + // 释放缓存锁 if p.cache != nil && attempt == 0 { hashKey := p.buildCacheKeyHashValue(ctx)