bucket

package
v1.5.1 Latest Latest
Warning

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

Go to latest
Published: Feb 15, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Example

Example demonstrates basic usage of the token bucket rate limiter

package main

import (
	"fmt"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	// Create a rate limiter that allows 10 requests per second with a burst of 5
	limiter, err := bucket.NewSafe(10, 5)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	// Check if a request is allowed (non-blocking)
	if limiter.Allow() {
		fmt.Println("Request allowed")
	} else {
		fmt.Println("Request denied")
	}

}
Output:

Request allowed
Example (Configuration)

Example_configuration demonstrates advanced configuration

package main

import (
	"fmt"
	"time"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	// Create with specific configuration
	config := bucket.Config{
		Rate:          bucket.Every(100 * time.Millisecond), // 1 token every 100ms
		Burst:         5,
		InitialTokens: 2, // Start with 2 tokens instead of full burst
	}

	limiter, err := bucket.NewWithConfigSafe(config)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	fmt.Printf("Initial tokens: %.0f\n", limiter.Tokens())
	fmt.Printf("Rate limit: %.1f/sec\n", limiter.Limit())
	fmt.Printf("Burst capacity: %d\n", limiter.Burst())

}
Output:

Initial tokens: 2
Rate limit: 10.0/sec
Burst capacity: 5
Example (DynamicConfiguration)

Example_dynamicConfiguration demonstrates changing limits at runtime

package main

import (
	"fmt"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	limiter, err := bucket.NewSafe(5, 10)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	fmt.Printf("Original rate: %.0f/sec, burst: %d\n", limiter.Limit(), limiter.Burst())

	// Increase the rate limit during high traffic
	limiter.SetLimit(20)
	fmt.Printf("Updated rate: %.0f/sec, burst: %d\n", limiter.Limit(), limiter.Burst())

	// Reduce burst size for stricter limiting
	limiter.SetBurst(5)
	fmt.Printf("Final rate: %.0f/sec, burst: %d\n", limiter.Limit(), limiter.Burst())

}
Output:

Original rate: 5/sec, burst: 10
Updated rate: 20/sec, burst: 10
Final rate: 20/sec, burst: 5
Example (MultipleTokens)

Example_multipleTokens demonstrates consuming multiple tokens at once

package main

import (
	"fmt"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	// Create a rate limiter (10 tokens per second, burst of 20)
	limiter, err := bucket.NewSafe(10, 20)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	// Try to consume 5 tokens at once
	if limiter.AllowN(5) {
		fmt.Println("Bulk operation allowed (5 tokens)")
	}

	// Check remaining tokens
	remaining := limiter.Tokens()
	fmt.Printf("Tokens remaining: %.0f\n", remaining)

}
Output:

Bulk operation allowed (5 tokens)
Tokens remaining: 15
Example (Reservation)

Example_reservation demonstrates the reservation pattern

package main

import (
	"fmt"
	"time"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	// Create a rate limiter (2 requests per second, burst of 3)
	limiter, err := bucket.NewSafe(2, 3)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	// Use all burst tokens
	for i := 0; i < 3; i++ {
		limiter.Allow()
	}

	// Make a reservation for the next request
	reservation := limiter.Reserve()
	if reservation.OK() {
		delay := reservation.Delay()
		fmt.Printf("Need to wait %v before next request\n", delay.Round(time.Millisecond))

		// Cancel the reservation if we don't want to wait
		reservation.Cancel()
		fmt.Println("Reservation canceled")
	}

}
Output:

Need to wait 500ms before next request
Reservation canceled
Example (Wait)

Example_wait demonstrates blocking until tokens are available

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/1mb-dev/goflow/pkg/ratelimit/bucket"
)

func main() {
	// Create a slow rate limiter (1 request per second, burst of 1)
	limiter, err := bucket.NewSafe(1, 1)
	if err != nil {
		panic(fmt.Sprintf("Failed to create limiter: %v", err))
	}

	ctx := context.Background()

	// First request succeeds immediately
	if err := limiter.Wait(ctx); err != nil {
		log.Fatal(err)
	}
	fmt.Println("First request processed")

	// Second request would need to wait, but we'll use a timeout
	ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
	defer cancel()

	if err := limiter.Wait(ctx); err != nil {
		fmt.Printf("Second request failed: %v\n", err)
	}

}
Output:

First request processed
Second request failed: context deadline exceeded

Index

Examples

Constants

This section is empty.

Variables

View Source
var Inf = Limit(math.Inf(1))

Inf is the infinite rate limit; it allows all events.

Functions

This section is empty.

Types

type Clock

type Clock interface {
	Now() time.Time
}

Clock provides the current time. It can be mocked for testing.

type Config

type Config struct {
	// Rate is the number of tokens added per second.
	Rate Limit

	// Burst is the maximum number of tokens that can be stored.
	Burst int

	// Clock provides the current time. If nil, SystemClock is used.
	Clock Clock

	// InitialTokens is the number of tokens to start with.
	// If negative, starts with full capacity.
	InitialTokens int
}

Config holds configuration options for creating a new Limiter.

type Limit

type Limit float64

Limit represents the maximum frequency of events per unit time. A zero Limit allows no events. Use Inf for unlimited rates.

func Every

func Every(interval time.Duration) Limit

Every converts a minimum time interval between events to a Limit.

type Limiter

type Limiter interface {
	// Allow reports whether an event may happen now. It does not block.
	Allow() bool

	// AllowN reports whether n events may happen now. It does not block.
	AllowN(n int) bool

	// Wait blocks until an event can happen. It returns an error
	// if the context is canceled or the deadline is exceeded.
	Wait(ctx context.Context) error

	// WaitN blocks until n events can happen. It returns an error
	// if the context is canceled or the deadline is exceeded.
	WaitN(ctx context.Context, n int) error

	// Reserve returns a Reservation that indicates how long the caller
	// must wait before n events can happen.
	Reserve() *Reservation

	// ReserveN returns a Reservation that indicates how long the caller
	// must wait before n events can happen.
	ReserveN(n int) *Reservation

	// SetLimit changes the rate limit. It preserves the current burst size.
	SetLimit(limit Limit)

	// SetBurst changes the burst size. It preserves the current rate limit.
	SetBurst(burst int)

	// Limit returns the current rate limit.
	Limit() Limit

	// Burst returns the current burst size.
	Burst() int

	// Tokens returns the number of tokens currently available.
	Tokens() float64
}

Limiter controls how frequently events are allowed to happen using a token bucket algorithm. It supports burst traffic by maintaining a reservoir of tokens that can be consumed quickly.

func NewSafe

func NewSafe(rate Limit, burst int) (Limiter, error)

NewSafe creates a new rate limiter with validation that returns an error instead of panicking. This is the recommended way to create rate limiters for production use.

func NewWithConfigSafe

func NewWithConfigSafe(config Config) (Limiter, error)

NewWithConfigSafe creates a new rate limiter with validation that returns an error instead of panicking. This is the recommended way to create rate limiters for production use.

type Reservation

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

Reservation holds information about an event that should happen in the future. It can be used to cancel the reservation or check when the event should occur.

func (*Reservation) Cancel

func (r *Reservation) Cancel()

Cancel cancels the reservation. This restores the tokens to the limiter if the reservation was valid.

func (*Reservation) Delay

func (r *Reservation) Delay() time.Duration

Delay returns the time until the reservation should act. If the reservation is not OK, Delay returns zero.

func (*Reservation) DelayFrom

func (r *Reservation) DelayFrom(now time.Time) time.Duration

DelayFrom returns the time until the reservation should act, measured from the given time.

func (*Reservation) OK

func (r *Reservation) OK() bool

OK returns whether the reservation is valid.

type SystemClock

type SystemClock struct{}

SystemClock implements Clock using the system time.

func (SystemClock) Now

func (SystemClock) Now() time.Time

Now returns the current system time.

Jump to

Keyboard shortcuts

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