Go · 1024 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package webhook
4
5 import "time"
6
7 // BackoffBase is the smallest retry delay; doubles per attempt.
8 const BackoffBase = 30 * time.Second
9
10 // BackoffMax caps the delay so a stale subscriber doesn't disappear
11 // for days at a time. The spec calls for 24 hours.
12 const BackoffMax = 24 * time.Hour
13
14 // Backoff returns the delay before retrying delivery `attempt` (1-
15 // indexed: the just-failed attempt counts as 1). Applies ±20% jitter
16 // so a fleet of webhooks pointed at one outage doesn't synchronize
17 // retries. `jitter` returns a value in [0, 1); pass `nil` for no jitter
18 // (deterministic schedule, useful in tests).
19 func Backoff(attempt int, jitter func() float64) time.Duration {
20 if attempt < 1 {
21 attempt = 1
22 }
23 d := BackoffBase
24 for i := 1; i < attempt; i++ {
25 d *= 2
26 if d >= BackoffMax {
27 d = BackoffMax
28 break
29 }
30 }
31 if d > BackoffMax {
32 d = BackoffMax
33 }
34 if jitter != nil {
35 mult := 0.8 + 0.4*jitter()
36 d = time.Duration(float64(d) * mult)
37 }
38 return d
39 }
40