speedbump

package module
Version: v2.0.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Dec 26, 2016 License: MIT Imports: 4 Imported by: 22

README

speedbump GoDoc

A Redis-backed Rate Limiter for Go

wercker status

Cool stuff

  • Backed by Redis, so it keeps track of requests across a cluster
  • Extensible timing functions. Includes defaults for tracking requests per second, minute, and hour
  • Works with IPv4, IPv6, or any other unique identifier
  • Example middleware included for Gin (See: ginbump) and Negroni (See: negronibump)

Notes

Usage

  • Get a working Redis server
  • Go get:
$ go get github.com/etcinit/speedbump
  • Include it in your code
package main

import (
	"fmt"
	"time"

	"github.com/etcinit/speedbump"
	"gopkg.in/redis.v5"
)

func main() {
	client := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})
	hasher := speedbump.PerSecondHasher{}

	// Here we create a limiter that will only allow 5 requests per second
	limiter := speedbump.NewLimiter(client, hasher, 5)

	for {
		// This example has a hardcoded IP, but you would replace it with the IP
		// of a client on a real case.
		success, err := limiter.Attempt("127.0.0.1")

		if err != nil {
			panic(err)
		}

		if success {
			fmt.Println("Successful!")
		} else {
			fmt.Println("Limited! :(")
		}

		time.Sleep(time.Millisecond * time.Duration(100))
	}
}
  • Output:
Successful!
Successful!
Successful!
Successful!
Successful!
Successful!
Limited! :(
Limited! :(
Limited! :(
Limited! :(
Limited! :(
Successful!
Successful!
Successful!
Successful!
Successful!
Successful!
Limited! :(
Limited! :(
Limited! :(
Limited! :(
Successful!
Successful!
...

Documentation

Overview

Package speedbump provides a Redis-backed rate limiter.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type PerHourHasher

type PerHourHasher struct {
	Clock clock.Clock
}

PerHourHasher generates hashes per hour. This means you can keep track of N request per hour.

func (PerHourHasher) Duration

func (h PerHourHasher) Duration() time.Duration

Duration gets the duration of each period.

func (PerHourHasher) Hash

func (h PerHourHasher) Hash(id string) string

Hash generates the hash for the current period and client.

type PerMinuteHasher

type PerMinuteHasher struct {
	Clock clock.Clock
}

PerMinuteHasher generates hashes per minute. This means you can keep track of N request per minute.

func (PerMinuteHasher) Duration

func (h PerMinuteHasher) Duration() time.Duration

Duration gets the duration of each period.

func (PerMinuteHasher) Hash

func (h PerMinuteHasher) Hash(id string) string

Hash generates the hash for the current period and client.

type PerSecondHasher

type PerSecondHasher struct {
	// Clock is the time reference that will be used by the hasher. If it is
	// not provided, the hashing function will use the default time. This can
	// be replaced with a mock clock object for testing.
	Clock clock.Clock
}

PerSecondHasher generates hashes per second. This means you can keep track of N request per second.

Example

The following example shows how to create mock hashers for testing the rate limiter in your code:

// Create a mock clock.
mock := clock.NewMock()

// Create a new per second hasher with the mock clock.
hasher := PerMinuteHasher{
	Clock: mock,
}

// Generate two consecutive hashes. On most systems, the following should
// generate two identical hashes.
hashOne := hasher.Hash("127.0.0.1")
hashTwo := hasher.Hash("127.0.0.1")

// Now we push the clock forward by a minute (time travel).
mock.Add(time.Minute)

// The third hash should be different now.
hashThree := hasher.Hash("127.0.0.1")

fmt.Println(hashOne == hashTwo)
fmt.Println(hashOne == hashThree)
Output:

true
false

func (PerSecondHasher) Duration

func (h PerSecondHasher) Duration() time.Duration

Duration gets the duration of each period.

func (PerSecondHasher) Hash

func (h PerSecondHasher) Hash(id string) string

Hash generates the hash for the current period and client.

type RateHasher

type RateHasher interface {
	// Hash is the hashing function.
	Hash(id string) string
	// Duration returns the duration of each period. This is used to determine
	// when to expire each counter key, and can also be used by other libraries
	// to generate messages that provide an estimate of when the limit will
	// expire.
	Duration() time.Duration
}

RateHasher is an object capable of generating a hash that uniquely identifies a counter to track the number of requests for an id over a certain time interval. The input of the Hash function can be any unique id, such as an IP address.

type RateLimiter

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

RateLimiter is a Redis-backed rate limiter.

func NewLimiter

func NewLimiter(
	client *redis.Client,
	hasher RateHasher,
	max int64,
) *RateLimiter

NewLimiter creates a new instance of a rate limiter.

Example
// Create a Redis client.
client := createClient()

// Create a new hasher.
hasher := PerSecondHasher{}

// Create a new limiter that will only allow 10 requests per second.
limiter := NewLimiter(client, hasher, 10)

fmt.Println(limiter.Attempt("127.0.0.1"))
Output:

true <nil>

func (*RateLimiter) Attempt

func (r *RateLimiter) Attempt(id string) (bool, error)

Attempt attempts to perform a request for an id and returns whether it was successful or not.

func (*RateLimiter) Attempted

func (r *RateLimiter) Attempted(id string) (int64, error)

Attempted returns the number of attempted requests for an id in the current period. Attempted does not count attempts that exceed the max requests in an interval and only returns the max count after this is reached.

func (*RateLimiter) Has

func (r *RateLimiter) Has(id string) (bool, error)

Has returns whether the rate limiter has seen a request for a specific id during the current period.

func (*RateLimiter) Left

func (r *RateLimiter) Left(id string) (int64, error)

Left returns the number of remaining requests for id during a current period.

Directories

Path Synopsis
Package ginbump provides an example Speedbump middleware for the Gin framework.
Package ginbump provides an example Speedbump middleware for the Gin framework.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL