redis_rate

package module
v11.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2023 License: BSD-2-Clause Imports: 8 Imported by: 0

README

Rate limiting for go-redis

PkgGoDev

This package is a fork of go-redis/redis_rate.

This go-redis/redis_rate was based on rwz/redis-gcra and implements GCRA (aka leaky bucket) for rate limiting based on Redis. The code requires Redis version 3.2 or newer since it relies on replicate_commands feature.

Fork Features

  • Pipeling: Check if you can allow multiple limits or concurrency checks all at once in a single Redis pipelined call.
  • Concurrency Limits: Limit the number of concurrent requests.
  • General cleanup for modern Go.

Example

package redis_rate_test

import (
	"context"
	"fmt"

	"github.com/redis/go-redis/v9"
	"github.com/ductone/redis_rate/v11"
)

func ExampleNewLimiter() {
	ctx := context.Background()
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})
	_ = rdb.FlushDB(ctx).Err()

	limiter := redis_rate.New(rdb)
	res, err := limiter.Allow(ctx, "project:123", redis_rate.PerSecond(10))
	if err != nil {
		panic(err)
	}
	fmt.Println("allowed", res.Allowed, "remaining", res.Remaining)
	// Output: allowed 1 remaining 9
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrScriptFailed = errors.New("redis_rate: invalid result from SCRIPT EXISTS in pipeline")
View Source
var ErrTooManyRetries = errors.New("redis_rate: pipeline too many retries to load scripts")

Functions

func WithConcurrencyPrefix added in v11.0.2

func WithConcurrencyPrefix(concurrentPrefix string) func(*Limiter)

WithConcurrencyPrefix sets the prefix for concurrency limit keys. If unset the default is "concurrency:".

func WithRatePrefix added in v11.0.2

func WithRatePrefix(ratePrefix string) func(*Limiter)

WithRatePrefix sets the prefix for rate limit keys when using the Limiter. If unset the default is "rate:".

Types

type ConcurrencyLimit added in v11.0.2

type ConcurrencyLimit struct {
	Max int64
	// RequestMaxDuration is the time period in seconds over which the a request must complete.  If unset it defaults to 30 seconds.
	RequestMaxDuration time.Duration
}

type ConcurrencyResult added in v11.0.2

type ConcurrencyResult struct {
	// Name of the key used for this result.
	Key string

	// Request ID used for this result.
	RequestID string

	// Limit is the limit that was used to obtain this result.
	Limit ConcurrencyLimit

	// Allowed is the number of events that may happen at time now.
	Allowed bool

	// Used is the number of events that have already happened at time now.
	Used int64

	// Remaining is the maximum number of requests that could be
	// permitted instantaneously for this key given the current
	// state. For example, if a rate limiter allows 10 requests per
	// second and has already received 6 requests for this key this
	// second, Remaining would be 4.
	Remaining int64
}

type Limit

type Limit struct {
	Rate   int
	Burst  int
	Period time.Duration
}

func PerHour

func PerHour(rate int) Limit

func PerMinute

func PerMinute(rate int) Limit

func PerSecond

func PerSecond(rate int) Limit

func (Limit) IsZero

func (l Limit) IsZero() bool

func (Limit) String

func (l Limit) String() string

type Limiter

type Limiter struct {
	// contains filtered or unexported fields
}

Limiter controls how frequently events are allowed to happen.

func New added in v11.0.2

func New(rdb RedisClientConn, options ...func(*Limiter)) *Limiter

New returns a new Limiter.

Example
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
	Addr: "localhost:6379",
})
_ = rdb.FlushDB(ctx).Err()

limiter := redis_rate.New(rdb)
res, err := limiter.Allow(ctx, "project:123", redis_rate.PerSecond(10))
if err != nil {
	panic(err)
}
fmt.Println("allowed", res.Allowed, "remaining", res.Remaining)
Output:

allowed 1 remaining 9

func (*Limiter) Allow

func (l *Limiter) Allow(ctx context.Context, key string, limit Limit) (*Result, error)

Allow is a shortcut for AllowN(ctx, key, limit, 1).

func (*Limiter) AllowAtMost

func (l *Limiter) AllowAtMost(
	ctx context.Context,
	key string,
	limit Limit,
	n int,
) (*Result, error)

AllowAtMost reports whether at most n events may happen at time now. It returns number of allowed events that is less than or equal to n.

func (*Limiter) AllowN

func (l *Limiter) AllowN(
	ctx context.Context,
	key string,
	limit Limit,
	n int,
) (*Result, error)

AllowN reports whether n events may happen at time now.

func (*Limiter) LoadScripts

func (l *Limiter) LoadScripts(ctx context.Context) error

func (*Limiter) Pipeline added in v11.0.2

func (l *Limiter) Pipeline() Pipeline

func (*Limiter) Release added in v11.0.2

func (tk *Limiter) Release(ctx context.Context, key string, requestID string, limit ConcurrencyLimit) error

func (*Limiter) Reset

func (l *Limiter) Reset(ctx context.Context, key string) error

Reset gets a key and reset all limitations and previous usages.

func (*Limiter) Take added in v11.0.2

func (tk *Limiter) Take(ctx context.Context, key string, requestID string, limit ConcurrencyLimit) (ConcurrencyResult, error)

type Pipeline added in v11.0.2

type Pipeline interface {
	Allow(ctx context.Context,
		key string,
		limit Limit,
	) *Result

	Take(ctx context.Context, key string, requestID string, limit ConcurrencyLimit) *ConcurrencyResult

	Release(ctx context.Context, key string, requestID string)

	Exec(ctx context.Context) error
}

type RedisClientConn

type RedisClientConn interface {
	Pipeline() redis.Pipeliner
	Pipelined(ctx context.Context, fn func(redis.Pipeliner) error) ([]redis.Cmder, error)

	Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
	EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd
	ScriptExists(ctx context.Context, hashes ...string) *redis.BoolSliceCmd
	ScriptLoad(ctx context.Context, script string) *redis.StringCmd
	Del(ctx context.Context, keys ...string) *redis.IntCmd

	EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
	EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd
}

type Result

type Result struct {
	// Name of the key used for this result.
	Key string

	// Limit is the limit that was used to obtain this result.
	Limit Limit

	// Allowed is the number of events that may happen at time now.
	Allowed int64

	// Used is the number of events that have already happened at time now.
	Used int64

	// Remaining is the maximum number of requests that could be
	// permitted instantaneously for this key given the current
	// state. For example, if a rate limiter allows 10 requests per
	// second and has already received 6 requests for this key this
	// second, Remaining would be 4.
	Remaining int64

	// RetryAfter is the time until the next request will be permitted.
	// It should be -1 unless the rate limit has been exceeded.
	RetryAfter time.Duration

	// ResetAfter is the time until the RateLimiter returns to its
	// initial state for a given key. For example, if a rate limiter
	// manages requests per second and received one request 200ms ago,
	// Reset would return 800ms. You can also think of this as the time
	// until Limit and Remaining will be equal.
	ResetAfter time.Duration
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL