TokenBucket limiter with burst capacity and refill

Go
package ratelimit

import (
    "sync"
    "time"
)

// Bucket is a token bucket: it allows bursts up to capacity while refilling at
// ratePerSec tokens per second.
type Bucket struct {
    mu       sync.Mutex
    capacity float64
    rate     float64
    tokens   float64
    last     time.Time
}

// NewBucket starts with a full bucket, so the first capacity calls succeed.
func NewBucket(capacity, ratePerSec float64) *Bucket {
    return &Bucket{capacity: capacity, rate: ratePerSec, tokens: capacity, last: time.Now()}
}

// Allow consumes n tokens if enough have accrued, otherwise it returns false.
func (b *Bucket) Allow(n float64) bool {
    b.mu.Lock()
    defer b.mu.Unlock()
    now := time.Now()
    b.tokens = min(b.capacity, b.tokens+now.Sub(b.last).Seconds()*b.rate)
    b.last = now
    if b.tokens < n {
        return false
    }
    b.tokens -= n
    return true
}