Documentation
¶
Index ¶
- Constants
- Variables
- func SetPerTokenLimitsForTest(rl *RateLimiter, maxConcurrent int, maxPerWindow int64)
- type ConcurrencyLimitError
- type PerTokenScope
- type RateLimitError
- type RateLimiter
- func (rl *RateLimiter) Acquire(ctx context.Context) (func(), error)
- func (rl *RateLimiter) AcquireForSubject(ctx context.Context, subject string) (func(), PerTokenScope, error)
- func (rl *RateLimiter) SetPerTokenLimits(maxConcurrent int, maxPerWindow int64)
- func (rl *RateLimiter) Stats() Stats
- func (rl *RateLimiter) String() string
- type Stats
Constants ¶
const DefaultAcquireTimeout = 100 * time.Millisecond
Variables ¶
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 ¶
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 ¶
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 (*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.