go.temporal.io/server@v1.23.0/common/quotas/dynamic_rate_limiter_impl.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package quotas 26 27 import ( 28 "context" 29 "time" 30 ) 31 32 const ( 33 defaultRefreshInterval = time.Minute 34 defaultIncomingRateBurstRatio = float64(2) 35 defaultOutgoingRateBurstRatio = float64(1) 36 ) 37 38 type ( 39 // DynamicRateLimiterImpl implements a dynamic config wrapper around the rate limiter 40 DynamicRateLimiterImpl struct { 41 rateBurstFn RateBurst 42 refreshInterval time.Duration 43 44 refreshTimer *time.Timer 45 rateLimiter *RateLimiterImpl 46 } 47 ) 48 49 var _ RateLimiter = (*DynamicRateLimiterImpl)(nil) 50 51 // NewDynamicRateLimiter returns a rate limiter which handles dynamic config 52 func NewDynamicRateLimiter( 53 rateBurstFn RateBurst, 54 refreshInterval time.Duration, 55 ) *DynamicRateLimiterImpl { 56 rateLimiter := &DynamicRateLimiterImpl{ 57 rateBurstFn: rateBurstFn, 58 refreshInterval: refreshInterval, 59 60 refreshTimer: time.NewTimer(refreshInterval), 61 rateLimiter: NewRateLimiter(rateBurstFn.Rate(), rateBurstFn.Burst()), 62 } 63 return rateLimiter 64 } 65 66 // NewDefaultIncomingRateLimiter returns a default rate limiter 67 // for incoming traffic 68 func NewDefaultIncomingRateLimiter( 69 rateFn RateFn, 70 ) *DynamicRateLimiterImpl { 71 return NewDynamicRateLimiter( 72 NewDefaultIncomingRateBurst(rateFn), 73 defaultRefreshInterval, 74 ) 75 } 76 77 // NewDefaultOutgoingRateLimiter returns a default rate limiter 78 // for outgoing traffic 79 func NewDefaultOutgoingRateLimiter( 80 rateFn RateFn, 81 ) *DynamicRateLimiterImpl { 82 return NewDynamicRateLimiter( 83 NewDefaultOutgoingRateBurst(rateFn), 84 defaultRefreshInterval, 85 ) 86 } 87 88 // Allow immediately returns with true or false indicating if a rate limit 89 // token is available or not 90 func (d *DynamicRateLimiterImpl) Allow() bool { 91 d.maybeRefresh() 92 return d.rateLimiter.Allow() 93 } 94 95 // AllowN immediately returns with true or false indicating if n rate limit 96 // token is available or not 97 func (d *DynamicRateLimiterImpl) AllowN(now time.Time, numToken int) bool { 98 d.maybeRefresh() 99 return d.rateLimiter.AllowN(now, numToken) 100 } 101 102 // Reserve reserves a rate limit token 103 func (d *DynamicRateLimiterImpl) Reserve() Reservation { 104 d.maybeRefresh() 105 return d.rateLimiter.Reserve() 106 } 107 108 // ReserveN reserves n rate limit token 109 func (d *DynamicRateLimiterImpl) ReserveN(now time.Time, numToken int) Reservation { 110 d.maybeRefresh() 111 return d.rateLimiter.ReserveN(now, numToken) 112 } 113 114 // Wait waits up till deadline for a rate limit token 115 func (d *DynamicRateLimiterImpl) Wait(ctx context.Context) error { 116 d.maybeRefresh() 117 return d.rateLimiter.Wait(ctx) 118 } 119 120 // WaitN waits up till deadline for n rate limit token 121 func (d *DynamicRateLimiterImpl) WaitN(ctx context.Context, numToken int) error { 122 d.maybeRefresh() 123 return d.rateLimiter.WaitN(ctx, numToken) 124 } 125 126 // Rate returns the rate per second for this rate limiter 127 func (d *DynamicRateLimiterImpl) Rate() float64 { 128 return d.rateLimiter.Rate() 129 } 130 131 // Burst returns the burst for this rate limiter 132 func (d *DynamicRateLimiterImpl) Burst() int { 133 return d.rateLimiter.Burst() 134 } 135 136 func (d *DynamicRateLimiterImpl) Refresh() { 137 d.rateLimiter.SetRateBurst(d.rateBurstFn.Rate(), d.rateBurstFn.Burst()) 138 } 139 140 func (d *DynamicRateLimiterImpl) maybeRefresh() { 141 select { 142 case <-d.refreshTimer.C: 143 d.refreshTimer.Reset(d.refreshInterval) 144 d.Refresh() 145 146 default: 147 // noop 148 } 149 }