counter

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2022 License: MIT Imports: 7 Imported by: 0

README

go-counter

Build Status Coverage Status Go Reference Go Report Card

Distributed rate limiting using Redis.

Example usage:

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/da440dil/go-counter"
	"github.com/go-redis/redis/v8"
)

func main() {
	client := redis.NewClient(&redis.Options{})
	defer client.Close()

	ctx := context.Background()
	key := "key"
	err := client.Del(ctx, key).Err()
	requireNoError(err)

	// Create limiter with 2 limits.
	limiter := counter.NewLimiter(
		client,
		// First limit: no more than 3 limiter calls within 1 second.
		counter.WithLimit(time.Second, 3),
		// Second limit: no more than 5 limiter calls within 2 seconds.
		counter.WithLimit(time.Second*2, 5),
	)

	limit := func() {
		r, err := limiter.Limit(ctx, key)
		requireNoError(err)
		fmt.Printf(
			"Result: { ok: %v, counter: %v, remainder: %v, ttl: %v }\n",
			r.OK(), r.Counter(), r.Remainder(), r.TTL(),
		)
	}
	limitN := func(n int) {
		var wg sync.WaitGroup
		wg.Add(n)
		for i := 0; i < n; i++ {
			go func() {
				defer wg.Done()
				limit()
			}()
		}
		wg.Wait()
	}

	limitN(4)
	time.Sleep(time.Second) // wait for the next window to start
	limitN(2)
	// Output:
	// Result: { ok: true, counter: 1, remainder: 2, ttl: 1s }
	// Result: { ok: true, counter: 3, remainder: 0, ttl: 998ms }
	// Result: { ok: true, counter: 2, remainder: 1, ttl: 998ms }
	// Result: { ok: false, counter: 3, remainder: 0, ttl: 998ms }
	// Result: { ok: true, counter: 5, remainder: 0, ttl: 993ms }
	// Result: { ok: false, counter: 5, remainder: 0, ttl: 993ms }
}

func requireNoError(err error) {
	if err != nil {
		panic(err)
	}
}

Documentation

Overview

Package counter provides functions for distributed rate limiting.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnexpectedRedisResponse = errors.New("counter: unexpected redis response")

ErrUnexpectedRedisResponse is the error returned when Redis command returns response of unexpected type.

Functions

func WithFixedWindow added in v0.6.0

func WithFixedWindow() func(*params)

WithFixedWindow sets fixed window algorithm for the limit.

func WithLimit added in v0.7.0

func WithLimit(size time.Duration, limit uint, options ...func(*params)) *params

WithLimit creates parameters to build a limit.

By default a limit uses fixed window algorithm, may be set with options. Each limit is created with pseudo-random name which may be set with options. The rate of decreasing the window size on each next application of the limit by default equal 1, may be set with options.

func WithName added in v0.6.0

func WithName(name string) func(*params)

WithName sets unique name for the limit, every Redis key will be prefixed with this name.

func WithRate added in v0.6.0

func WithRate(rate uint) func(*params)

WithRate sets the rate of decreasing the window size on each next application of the limit.

func WithSlidingWindow added in v0.6.0

func WithSlidingWindow() func(*params)

WithSlidingWindow sets sliding window algorithm for the limit.

Types

type Counter

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

Counter implements distributed counter.

func FixedWindow added in v0.2.0

func FixedWindow(client RedisClient, size time.Duration, limit uint) *Counter

FixedWindow creates new counter which implements distributed counter using fixed window algorithm.

func SlidingWindow added in v0.2.0

func SlidingWindow(client RedisClient, size time.Duration, limit uint) *Counter

SlidingWindow creates new counter which implements distributed counter using sliding window algorithm.

func (*Counter) Count

func (c *Counter) Count(ctx context.Context, key string, value int) (Result, error)

Count increments key value by specified value.

type Limiter added in v0.5.0

type Limiter interface {
	// Limit applies the limit.
	Limit(ctx context.Context, key string) (Result, error)
}

Limiter implements distributed rate limiting.

func NewLimiter added in v0.5.0

func NewLimiter(client RedisClient, first *params, rest ...*params) Limiter

NewLimiter creates new limiter which implements distributed rate limiting.

type RedisClient added in v0.2.0

type RedisClient interface {
	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
}

RedisClient is redis scripter interface.

type Result added in v0.2.0

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

Result is counter value increment result.

func (Result) Counter added in v0.2.0

func (r Result) Counter() int64

Counter is current counter value.

func (Result) OK added in v0.2.0

func (r Result) OK() bool

OK is operation success flag.

func (Result) Remainder added in v0.5.0

func (r Result) Remainder() int64

Remainder is diff between limit and current counter value.

func (Result) TTL added in v0.2.0

func (r Result) TTL() time.Duration

TTL of the current window.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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