返回 DeepSeek-Reasonix
stale_connection.go
根目录 / internal / provider / stale_connection.go
1 package provider
2
3 import (
4 "context"
5 "errors"
6 "io"
7 "net/http/httptrace"
8 "sync/atomic"
9 )
10
11 // connectionProbe records what the transport did with one request attempt:
12 // whether it went out on a pooled connection that had been idle, and whether
13 // any response byte came back on it.
14 type connectionProbe struct {
15 idleReuse atomic.Bool
16 responded atomic.Bool
17 }
18
19 func (p *connectionProbe) attach(ctx context.Context) context.Context {
20 return httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
21 GotConn: func(info httptrace.GotConnInfo) {
22 p.idleReuse.Store(info.Reused && info.WasIdle)
23 },
24 GotFirstResponseByte: func() { p.responded.Store(true) },
25 })
26 }
27
28 // staleIdleConnection reports whether err is a pooled idle connection that the
29 // peer or an intermediary had already dropped: it closed before answering
30 // anything. The request may still have been delivered, so the caller resends
31 // at most once.
32 func (p *connectionProbe) staleIdleConnection(ctx context.Context, err error) bool {
33 if err == nil || ctx.Err() != nil || !p.idleReuse.Load() || p.responded.Load() {
34 return false
35 }
36 if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) {
37 return true
38 }
39 for _, closed := range closedConnectionErrnos {
40 if errors.Is(err, closed) {
41 return true
42 }
43 }
44 return false
45 }
46
46 lines GO