throttle

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: LGPL-2.1 Imports: 3 Imported by: 0

README

throttle

Limit requests to certain time intervals, both globally and per entity.

Rationale

Consider a website with a contact form, which is mostly used by spammers, and occasionally by real users. There are two issues:

  1. The server must not be overwhelmed by spam.
  2. The real user must not be delayed by spam countermeasures.

This throttle library achieves both by defining two intervals:

  1. A global interval, after which a new request can be sent.
  2. A entity-scoped interval, after which a particular user can send a new request.

This is achieved by defining a short global and a much longer by-entity interval.

Example

Define a throttle allowing requests coming in every second, but only once per minute for a single entity:

t := throttle.New[*net.IP, *http.Request](time.Second, time.Minute)

The throttle identifies the entities by their IPv4 addresses and throttles HTTP requests.

Now consider a legitimate user in the following pseude-HTTP handling code:

// demo boilerplate
ip := net.IPv4(192, 168, 1, 100)
req, _ := http.NewRequest(http.MethodGet, "/index.html", bytes.NewBufferString(""))

// http handling code
r, err := t.Await(&ip, &req, 5*time.Second)
if err == throttle.TimeoutError {
    fmt.Fprintf(os.Stderr, "timeout")
}
fmt.Println("serve request", r)

The request will be served without any delay, but then Alice needs to wait for a minute for her second request.

Check out the test cases in throttle_test.go for further understanding.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var TimeoutError error

Functions

This section is empty.

Types

type Throttle

type Throttle[T comparable, V any] struct {
	// GlobalSpawn is a channel that spawns tokens at GlobalRate.
	GlobalSpawn *time.Ticker

	// EntitySpawnMux is a mutex over EntitySpawn.
	EntitySpawnMux sync.RWMutex

	// EntitySpawn maps entities to their individual channel that spawns tokens at EntityRate.
	EntitySpawn map[T]*time.Ticker

	// EntityRate is the rate at which entity-specific tokens are spanwed.
	EntityRate time.Duration
}

Throttle allows to throttles the usage of values of type V identified by entities of type T.

func New

func New[T comparable, V any](globalRate, entityRate time.Duration) *Throttle[T, V]

New creates a new Throttle by defining its global and entity token spawn rate.

func (*Throttle[T, V]) Await

func (t *Throttle[T, V]) Await(entity T, value *V, timeout time.Duration) (*V, error)

Await waits for the throttle object to spawn both a token for the individual entity and globally. If those tokens are spawned within the given timeout, the given value is returned back. Otherwise, TimeoutError is returned. The first token (globally, per entity) is spawned immediately.

Jump to

Keyboard shortcuts

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