Go API Documentation

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

redis.UniversalClient

No comment on field.
locker

limiters.DistLocker

No comment on field.
logger

limiters.Logger

No comment on field.
clock

limiters.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

func(ctx context.Context, key string, rate float64, per float64) error

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

Uses: limiters.NewLockNoop, limiters.NewStdLogger, limiters.NewSystemClock.

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

Uses: limiters.FixedWindowIncrementer, limiters.LocalFixedWindow, limiters.NewFixedWindow, limiters.NewFixedWindowRedis, time.Duration, time.Second.

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

Uses: limiters.DistLocker, limiters.LeakyBucketStateBackend, limiters.LocalLeakyBucket, limiters.NewLeakyBucket, limiters.NewLeakyBucketRedis, time.Duration, time.Second, time.Sleep.

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

Uses: limiters.NewLockRedis, redis.NewPool.

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

Uses: limiters.LocalSlidingWindow, limiters.NewSlidingWindow, limiters.NewSlidingWindowRedis, limiters.SlidingWindowIncrementer, time.Duration, time.Second.

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

Uses: limiters.DistLocker, limiters.LocalTokenBucket, limiters.NewTokenBucket, limiters.NewTokenBucketRedis, limiters.TokenBucketStateBackend, time.Duration, time.Second.