ALL

Solo para leer y verificar. No puedes copiar, usar, modificar ni redistribuir este código. Aviso completo en la página principal.

tunnel/clock.go

SHA-256: 6856c8ce26b9bddc79576f98c8fa597e4609a3c1f070f3089ff3eb9e2892ad8e
67 líneas · 2130 bytes · Ver en GitHub

1package main
2
3import (
4 "context"
5 "math/rand/v2"
6 "time"
7)
8
9// clock is the node's source of time. Production uses the real one; the tests that cover hours (an outage of two hours, a grace of fifteen minutes,
10// a JWKS that goes stale) drive their own by hand, so nothing in the node reads the wall clock for a decision except through it. Socket deadlines are
11// not decisions of that kind: they stay on the real clock.
12type clock struct {
13 now func() time.Time
14 afterFunc func(d time.Duration, f func()) (stop func() bool)
15}
16
17func newClock(now func() time.Time, afterFunc func(d time.Duration, f func()) func() bool) clock {
18 if now == nil {
19 now = time.Now
20 }
21 if afterFunc == nil {
22 afterFunc = func(d time.Duration, f func()) func() bool { return time.AfterFunc(d, f).Stop }
23 }
24 return clock{now: now, afterFunc: afterFunc}
25}
26
27func (c clock) Now() time.Time { return c.now() }
28
29// AfterFunc runs f once, d from now on this clock, in its own goroutine. The returned function stops it and reports whether it did so in time.
30func (c clock) AfterFunc(d time.Duration, f func()) (stop func() bool) {
31 return c.afterFunc(max(d, 0), f)
32}
33
34// sleep waits d on this clock; it reports false when ctx ended first.
35func (c clock) sleep(ctx context.Context, d time.Duration) bool {
36 if ctx.Err() != nil {
37 return false
38 }
39 done := make(chan struct{})
40 stop := c.AfterFunc(d, func() { close(done) })
41 defer stop()
42 select {
43 case <-done:
44 return true
45 case <-ctx.Done():
46 return false
47 }
48}
49
50// jitter spreads d by up to +/- pct percent, so that a fleet of nodes or a loop restarted together does not stay in step.
51func jitter(d time.Duration, pct int) time.Duration {
52 if pct <= 0 || d <= 0 {
53 return d
54 }
55 span := int64(d) * int64(pct) / 100
56 return d + time.Duration(rand.Int64N(2*span+1)-span)
57}
58
59// backoff is the delay after the n-th failure in a row (n from 1): the policy's minimum, doubled each time, up to its maximum.
60func backoff(n int) time.Duration {
61 d := secs(policyData.Timing.BackoffMinS)
62 limit := secs(policyData.Timing.BackoffMaxS)
63 for i := 1; i < n && d < limit; i++ {
64 d *= 2
65 }
66 return min(d, limit)
67}