maglevt: subtract probe duration from inter-probe sleep

runProbeLoop used to sleep the full jittered interval after every
probe, so a 100ms --interval with a 30ms probe actually produced a
130ms period — the flag quietly lied about cadence and the effective
rate depended on backend latency. The fix subtracts result.Duration
from the sleep so the loop's period matches --interval. Probes that
overrun the interval clamp the sleep to zero and fire immediately
without trying to catch up on missed cycles, so a slow backend
doesn't get flooded with back-to-back retries exactly when it's
already struggling.
This commit is contained in:
2026-04-15 10:50:53 +02:00
parent 6b2b04b2d1
commit 695ebc4bd1

View File

@@ -123,6 +123,17 @@ func newHTTPClient(opts probeOpts) *http.Client {
// cancelled. Each completed probe posts a probeResultMsg into the
// tea.Program via send.
//
// The probe duration is subtracted from the sleep so the loop's
// *period* is the interval, not interval + probe time. If a 100ms
// interval probe takes 30ms, the next sleep is 70ms (minus jitter),
// not 100ms — otherwise a VIP with 30ms probes would actually fire
// every 130ms and the --interval flag would quietly lie. On the
// pathological case where a probe overruns the interval (slow VIP
// under load) we clamp the sleep to zero and fire the next probe
// immediately, but we never try to "catch up" by firing multiple
// back-to-back probes — that would flood an already-struggling
// backend right when it's slow.
//
// The loop honors the global `paused` flag by simply skipping the
// probe call while paused — the ticker keeps ticking so a resume
// picks up at the next natural tick boundary instead of fast-
@@ -141,6 +152,10 @@ func runProbeLoop(ctx context.Context, vip *vipInfo, opts probeOpts, send func(t
if !paused.Load() {
result := doProbe(ctx, vip, opts)
send(result)
sleepFor -= result.Duration
if sleepFor < 0 {
sleepFor = 0
}
}
select {
case <-ctx.Done():