(ctx context.Context, network *Network, shadowUpstreams []*upstream.Upstream, resp *common.NormalizedResponse)
| 14 | ) |
| 15 | |
| 16 | func (p *PreparedProject) executeShadowRequests(ctx context.Context, network *Network, shadowUpstreams []*upstream.Upstream, resp *common.NormalizedResponse) { |
| 17 | defer func() { |
| 18 | if r := recover(); r != nil { |
| 19 | p.Logger.Error().Msgf("panic while executing shadow requests: %v", r) |
| 20 | telemetry.MetricUnexpectedPanicTotal.WithLabelValues( |
| 21 | "shadow-upstreams", |
| 22 | fmt.Sprintf("network:%s", network.Label()), |
| 23 | common.ErrorFingerprint(r), |
| 24 | ).Inc() |
| 25 | } |
| 26 | }() |
| 27 | if resp == nil || len(shadowUpstreams) == 0 { |
| 28 | return |
| 29 | } |
| 30 | |
| 31 | resp.RLockWithTrace(ctx) |
| 32 | |
| 33 | // Derive the original request from the response |
| 34 | origReq := resp.Request() |
| 35 | if origReq == nil { |
| 36 | resp.RUnlock() |
| 37 | return |
| 38 | } |
| 39 | |
| 40 | method, _ := origReq.Method() |
| 41 | |
| 42 | // Compute the expected hash of the original upstream response once |
| 43 | originalSize, err := resp.Size(ctx) |
| 44 | if err != nil { |
| 45 | resp.RUnlock() |
| 46 | p.Logger.Error().Err(err).Msg("failed to compute hash for original response while executing shadow requests") |
| 47 | return |
| 48 | } |
| 49 | |
| 50 | resp.RUnlock() |
| 51 | |
| 52 | // Fire shadow requests concurrently |
| 53 | for _, ups := range shadowUpstreams { |
| 54 | allowed, err := ups.ShouldHandleMethod(method) |
| 55 | if err != nil { |
| 56 | p.Logger.Error().Err(err).Msg("failed to check if method is allowed for shadow upstream") |
| 57 | continue |
| 58 | } |
| 59 | if !allowed { |
| 60 | p.Logger.Debug().Str("method", method).Str("upstreamId", ups.Id()).Msg("method not allowed for shadow upstream") |
| 61 | continue |
| 62 | } |
| 63 | // Apply sample rate: skip this shadow upstream based on configured probability |
| 64 | sampleRate := 1.0 |
| 65 | if ups.Config().Shadow.SampleRate != nil { |
| 66 | sampleRate = *ups.Config().Shadow.SampleRate |
| 67 | } |
| 68 | if sampleRate < 1.0 && rand.Float64() >= sampleRate { |
| 69 | p.Logger.Debug(). |
| 70 | Str("method", method). |
| 71 | Str("upstreamId", ups.Id()). |
| 72 | Float64("sampleRate", sampleRate). |
| 73 | Msg("shadow request skipped due to sampling") |
no test coverage detected