...
1 package ratelimits
2
3 import (
4 "time"
5
6 "github.com/jmhodges/clock"
7 )
8
9
10
11
12 func maybeSpend(clk clock.Clock, rl limit, tat time.Time, cost int64) *Decision {
13 if cost < 0 || cost > rl.Burst {
14
15
16
17 panic("invalid cost for maybeSpend")
18 }
19 nowUnix := clk.Now().UnixNano()
20 tatUnix := tat.UnixNano()
21
22
23
24
25 if nowUnix > tatUnix {
26 tatUnix = nowUnix
27 }
28
29
30 costIncrement := rl.emissionInterval * cost
31
32
33 newTAT := tatUnix + costIncrement
34 difference := nowUnix - (newTAT - rl.burstOffset)
35
36 if difference < 0 {
37
38 residual := (nowUnix - (tatUnix - rl.burstOffset)) / rl.emissionInterval
39 return &Decision{
40 Allowed: false,
41 Remaining: residual,
42 RetryIn: -time.Duration(difference),
43 ResetIn: time.Duration(tatUnix - nowUnix),
44 newTAT: time.Unix(0, tatUnix).UTC(),
45 }
46 }
47
48
49 var retryIn time.Duration
50 residual := difference / rl.emissionInterval
51 if difference < costIncrement {
52 retryIn = time.Duration(costIncrement - difference)
53 }
54 return &Decision{
55 Allowed: true,
56 Remaining: residual,
57 RetryIn: retryIn,
58 ResetIn: time.Duration(newTAT - nowUnix),
59 newTAT: time.Unix(0, newTAT).UTC(),
60 }
61 }
62
63
64
65
66
67 func maybeRefund(clk clock.Clock, rl limit, tat time.Time, cost int64) *Decision {
68 if cost <= 0 || cost > rl.Burst {
69
70
71 panic("invalid cost for maybeRefund")
72 }
73 nowUnix := clk.Now().UnixNano()
74 tatUnix := tat.UnixNano()
75
76
77 if nowUnix > tatUnix {
78
79 return &Decision{
80 Allowed: false,
81 Remaining: rl.Burst,
82 RetryIn: time.Duration(0),
83 ResetIn: time.Duration(0),
84 newTAT: tat,
85 }
86 }
87
88
89 refundIncrement := rl.emissionInterval * cost
90
91
92 newTAT := tatUnix - refundIncrement
93
94
95 if newTAT < nowUnix {
96 newTAT = nowUnix
97 }
98
99
100 difference := nowUnix - (newTAT - rl.burstOffset)
101 residual := difference / rl.emissionInterval
102
103 return &Decision{
104 Allowed: (newTAT != tatUnix),
105 Remaining: residual,
106 RetryIn: time.Duration(0),
107 ResetIn: time.Duration(newTAT - nowUnix),
108 newTAT: time.Unix(0, newTAT).UTC(),
109 }
110 }
111
View as plain text