github.com/TykTechnologies/tyk/internal/rate/limiter
No package summary is available.
Package
Files: 5. Third party imports: 0. Imports from organisation: 1. Tests: 0. Benchmarks: 0.
Vars
var ErrLimitExhausted = limiters.ErrLimitExhausted
Types
Limiter
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| redis |
|
No comment on field. |
| locker |
|
No comment on field. |
| logger |
|
No comment on field. |
| clock |
|
No comment on field. |
type Limiter struct {
redis redis.UniversalClient
locker limiters.DistLocker
logger limiters.Logger
clock limiters.Clock
}
LimiterFunc
This type doesn't have documentation.
| Field name | Field type | Comment |
|---|---|---|
| type |
|
No comment on field. |
type LimiterFunc func(ctx context.Context, key string, rate float64, per float64) error
Functions
func NewLimiter
NewLimiter creates a new limiter object. It holds the redis client and the default non-distributed locks, logger, and a clock for supporting tests.
func NewLimiter(redis redis.UniversalClient) *Limiter {
return &Limiter{
redis: redis,
locker: limiters.NewLockNoop(),
logger: limiters.NewStdLogger(),
clock: limiters.NewSystemClock(),
}
}
Cognitive complexity: 1, Cyclomatic complexity: 1
func (*Limiter) FixedWindow
func (l *Limiter) FixedWindow(ctx context.Context, key string, rate float64, per float64) error {
var (
storage limiters.FixedWindowIncrementer
capacity = int64(rate)
ttl = time.Duration(per * float64(time.Second))
)
if l.redis != nil {
storage = limiters.NewFixedWindowRedis(l.redis, key)
} else {
storage = limiters.LocalFixedWindow(key)
}
limiter := limiters.NewFixedWindow(capacity, ttl, storage, l.clock)
// Rate limiter returns a zero duration and a possible ErrLimitExhausted when no tokens are available.
_, err := limiter.Limit(ctx)
return err
}
Cognitive complexity: 4, Cyclomatic complexity: 2
func (*Limiter) LeakyBucket
func (l *Limiter) LeakyBucket(ctx context.Context, key string, rate float64, per float64) error {
var (
storage limiters.LeakyBucketStateBackend
locker limiters.DistLocker
capacity = int64(rate)
ttl = time.Duration(per * float64(time.Second))
outputRate = time.Duration((per / rate) * float64(time.Second))
raceCheck = false
)
locker = l.Locker(key)
if l.redis != nil {
storage = limiters.NewLeakyBucketRedis(l.redis, key, ttl, raceCheck)
} else {
storage = limiters.LocalLeakyBucket(key)
}
limiter := limiters.NewLeakyBucket(capacity, outputRate, locker, storage, l.clock, l.logger)
// Rate limiter returns ErrLimitExhausted, or queues the request.
res, err := limiter.Limit(ctx)
if err == nil {
time.Sleep(res)
}
return err
}
Cognitive complexity: 6, Cyclomatic complexity: 3
func (*Limiter) Locker
Locker will ensure a distributed lock with redis, using redsync for a key. If redis is not in use, fallback is done to use the default locker.
func (l *Limiter) Locker(name string) limiters.DistLocker {
if l.redis != nil {
return limiters.NewLockRedis(redis.NewPool(l.redis), name+"-lock")
}
return l.locker
}
Cognitive complexity: 2, Cyclomatic complexity: 2
func (*Limiter) SlidingWindow
func (l *Limiter) SlidingWindow(ctx context.Context, key string, rate float64, per float64) error {
var (
storage limiters.SlidingWindowIncrementer
capacity = int64(rate)
ttl = time.Duration(per * float64(time.Second))
)
if l.redis != nil {
storage = limiters.NewSlidingWindowRedis(l.redis, key)
} else {
storage = limiters.LocalSlidingWindow(key)
}
// TODO: when doing rate sliding rate limits, the counts for two windows are
// used, the full count of the current window, and based on % of window
// time that has elapsed, a reduced previous window count.
//
// the epsilon value is used to allow some requests to go over the defined
// rate limit at any point of the calculation (start of window, end of ...).
limiter := limiters.NewSlidingWindow(capacity, ttl, storage, l.clock, 0)
// Rate limiter returns a zero duration and a possible ErrLimitExhausted when no tokens are available.
_, err := limiter.Limit(ctx)
return err
}
Cognitive complexity: 4, Cyclomatic complexity: 2
func (*Limiter) TokenBucket
func (l *Limiter) TokenBucket(ctx context.Context, key string, rate float64, per float64) error {
var (
storage limiters.TokenBucketStateBackend
locker limiters.DistLocker
capacity = int64(rate)
ttl = time.Duration(per * float64(time.Second))
raceCheck = false
)
locker = l.Locker(key)
if l.redis != nil {
storage = limiters.NewTokenBucketRedis(l.redis, key, ttl, raceCheck)
} else {
storage = limiters.LocalTokenBucket(key)
}
limiter := limiters.NewTokenBucket(capacity, ttl, locker, storage, l.clock, l.logger)
// Rate limiter returns a zero duration and a possible ErrLimitExhausted when no tokens are available.
_, err := limiter.Limit(ctx)
return err
}
Cognitive complexity: 4, Cyclomatic complexity: 2