ratelimit

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Apr 12, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultAcquireTimeout = 100 * time.Millisecond

Variables

View Source
var (
	ErrConcurrencyLimitExceeded = errors.New("concurrency limit exceeded")
	ErrRateLimitExceeded        = errors.New("rate limit exceeded")
)

Functions

func SetPerTokenLimitsForTest

func SetPerTokenLimitsForTest(rl *RateLimiter, maxConcurrent int, maxPerWindow int64)

SetPerTokenLimitsForTest mutates the per-token sub-layer on a RateLimiter. Production code configures these via CLOCKIFY_PER_TOKEN_* env vars through FromEnv(); this helper exists so other packages' tests can drive the per-subject path without exporting the fields themselves.

Types

type ConcurrencyLimitError

type ConcurrencyLimitError struct {
	MaxConcurrent int
	Cause         error
}

func (*ConcurrencyLimitError) Error

func (e *ConcurrencyLimitError) Error() string

func (*ConcurrencyLimitError) Is

func (e *ConcurrencyLimitError) Is(target error) bool

func (*ConcurrencyLimitError) Unwrap

func (e *ConcurrencyLimitError) Unwrap() error

type PerTokenScope

type PerTokenScope string

PerTokenScope describes the sub-layer an AcquireForSubject rejection originated from so callers (enforcement.Pipeline, metrics) can label rejections consistently without inspecting error strings.

const (
	ScopeGlobal     PerTokenScope = "global"
	ScopePerToken   PerTokenScope = "per_token"
	ScopeUnknown    PerTokenScope = "unknown"
	ScopeConcurrent               = "concurrency"
)

type RateLimitError

type RateLimitError struct {
	MaxPerWindow int64
	WindowMillis int64
}

func (*RateLimitError) Error

func (e *RateLimitError) Error() string

func (*RateLimitError) Is

func (e *RateLimitError) Is(target error) bool

type RateLimiter

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

RateLimiter controls concurrent access and fixed-window call volume to the Clockify API. A nil *RateLimiter is safe to use — Acquire returns a no-op release function and nil error.

func FromEnv

func FromEnv() *RateLimiter

FromEnv builds a RateLimiter from environment variables.

CLOCKIFY_MAX_CONCURRENT  – default 10 (0 disables concurrency limit)
CLOCKIFY_RATE_LIMIT      – default 120 (0 disables fixed-window limit)

Returns nil if both values are 0 (rate limiting fully disabled).

func FromEnvWithAcquireTimeout

func FromEnvWithAcquireTimeout(acquireTimeout time.Duration) *RateLimiter

func New

func New(maxConcurrent int, maxPerWindow int64, windowMillis int64) *RateLimiter

New creates a RateLimiter with explicit parameters.

maxConcurrent – buffered-channel capacity (simultaneous in-flight calls)
maxPerWindow  – maximum calls allowed within each fixed window
windowMillis  – fixed-window length in milliseconds

func NewWithAcquireTimeout

func NewWithAcquireTimeout(maxConcurrent int, maxPerWindow int64, windowMillis int64, acquireTimeout time.Duration) *RateLimiter

func (*RateLimiter) Acquire

func (rl *RateLimiter) Acquire(ctx context.Context) (func(), error)

Acquire reserves a slot. The returned function must be called to release the slot when work is done. Returns an error if the concurrency or current fixed-window limit would be exceeded.

func (*RateLimiter) AcquireForSubject

func (rl *RateLimiter) AcquireForSubject(ctx context.Context, subject string) (func(), PerTokenScope, error)

AcquireForSubject extends Acquire with an optional per-subject layer: first it runs the full global acquire path (semaphore + window), then it also checks a subject-scoped sub-limiter so a single authenticated client cannot monopolise the global budget. An empty subject skips the per-token layer entirely (back-compat with unauthenticated paths).

When the per-token layer rejects, AcquireForSubject releases the global slot it already acquired before returning, so the global budget is never stranded on a per-token failure. The returned PerTokenScope identifies which layer rejected.

func (*RateLimiter) SetPerTokenLimits added in v0.7.0

func (rl *RateLimiter) SetPerTokenLimits(maxConcurrent int, maxPerWindow int64)

SetPerTokenLimits configures the per-subject sub-layer from an outside-the-constructor site. FromEnv applies the same values by reading CLOCKIFY_PER_TOKEN_{CONCURRENCY,RATE_LIMIT}; this setter exists for programmatic consumers (notably the W2-09 load harness at tests/load/) that need to drive the rate limiter without going through environment variables. Call before any Acquire* so the config is immutable during the call path. Setting either cap to 0 disables that dimension of the per-subject layer.

func (*RateLimiter) Stats

func (rl *RateLimiter) Stats() Stats

Stats returns a snapshot of the current limiter state.

func (*RateLimiter) String

func (rl *RateLimiter) String() string

String returns a human-readable description of the limiter's configuration.

type Stats

type Stats struct {
	Concurrent    int
	MaxConcurrent int
	WindowCount   int64
	MaxPerWindow  int64
	WindowMillis  int64
}

Stats describes a snapshot of the rate limiter's live counters. A zero Stats is returned for a nil receiver so callers do not need a nil guard.

Jump to

Keyboard shortcuts

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