VOOZH about

URL: https://deepwiki.com/hypervel/cache/4.3-rate-limiting

⇱ Rate Limiting | hypervel/cache | DeepWiki


Loading...
Menu

Rate Limiting

The rate limiting system provides a declarative API for defining rate limits through the Limit class. This class encapsulates rate limit configurations including maximum attempts, decay time windows, unique keys, and custom response callbacks. Rate limits are consumed by the RateLimiter class, which enforces them using the cache subsystem.

For distributed locking mechanisms, see Distributed Locking. For cache operations, see Repository Pattern.

Overview

The Limit class serves as a value object that defines rate limiting rules. It provides a fluent interface for configuring rate limits with sensible defaults and static factory methods for common time periods. The class is designed to be immutable after creation, with fluent methods returning the same instance with modified properties.


Sources: src/RateLimiting/Limit.php9-92 </old_str>

<old_str>

Static Factory Methods

The Limit class provides static factory methods for creating rate limits with common time windows. These methods improve code readability and reduce calculation errors when converting time units to minutes.

perMinute()

Creates a rate limit with a one-minute decay window:

Limit::perMinute(int $maxAttempts): static

Sources: src/RateLimiting/Limit.php44-47

This factory creates a Limit with decayMinutes = 1. Example: Limit::perMinute(60) allows 60 attempts per minute.

perHour()

Creates a rate limit with an hourly decay window:

Limit::perHour(int $maxAttempts, int $decayHours = 1): static

Sources: src/RateLimiting/Limit.php52-55

The decayHours parameter allows multi-hour windows. The decay minutes are calculated as 60 * $decayHours. Examples:

  • Limit::perHour(1000) - 1000 attempts per hour
  • Limit::perHour(5000, 2) - 5000 attempts per 2 hours

perDay()

Creates a rate limit with a daily decay window:

Limit::perDay(int $maxAttempts, int $decayDays = 1): static

Sources: src/RateLimiting/Limit.php60-63

The decayDays parameter allows multi-day windows. The decay minutes are calculated as 60 * 24 * $decayDays. Examples:

  • Limit::perDay(10000) - 10,000 attempts per day
  • Limit::perDay(50000, 7) - 50,000 attempts per week

none()

Creates an unlimited rate limit that never restricts access:

Limit::none(): Unlimited

Sources: src/RateLimiting/Limit.php68-71

This method returns an Unlimited instance (a subclass of Limit) rather than a standard Limit. The Unlimited class can be detected by consumers to bypass rate limiting checks entirely.

Decay Time Calculation

The following table shows how the factory methods calculate decay minutes:

Factory MethodFormulaExampleDecay Minutes
perMinute(n)n attempts / 1 minuteperMinute(60)1
perHour(n, h)n attempts / h hoursperHour(1000, 2)120
perDay(n, d)n attempts / d daysperDay(10000, 7)10,080

Sources: src/RateLimiting/Limit.php44-63 </old_str> <new_str>

Limit Class Structure

The Limit class contains four public properties that define a rate limiting rule:

PropertyTypeDescription
keystringUnique identifier for the rate limit (e.g., user ID, IP address)
maxAttemptsintMaximum number of attempts allowed within the decay window
decayMinutesintTime window in minutes before the rate limit resets
responseCallback?ClosureOptional callback to generate custom responses when limit is exceeded

Sources: src/RateLimiting/Limit.php14-29

The constructor accepts these values directly, with default values optimized for common use cases:

__construct(string $key = '', int $maxAttempts = 60, int $decayMinutes = 1)

Sources: src/RateLimiting/Limit.php34-39

The default configuration allows 60 attempts per minute, suitable for general API rate limiting scenarios. The empty key allows limiters to be created without immediate key assignment, which can be set later using the fluent by() method.

RateLimiter Class Structure

The RateLimiter class uses dependency injection to receive a cache factory and provides methods for tracking and enforcing rate limits:

PropertyTypePurpose
cacheCacheCache store for persisting rate limit data
limitersarrayNamed rate limiter configurations
MethodPurpose
attempt()Execute callback if not rate limited
tooManyAttempts()Check if key has exceeded limit
hit()Increment attempt counter
attempts()Get current attempt count
resetAttempts()Clear attempt counter
remaining()Get remaining attempts
clear()Clear all rate limit data for key
availableIn()Seconds until key is available

Sources: src/RateLimiter.php17-23 src/RateLimiter.php28-31

Fluent Configuration API

The Limit class provides fluent methods that modify the instance and return $this for method chaining. These methods allow limits to be customized after creation.

Setting the Key with by()

The by() method sets the unique identifier for the rate limit:

by(string $key): static

Sources: src/RateLimiting/Limit.php76-81

This method is particularly useful when creating limits without a key initially:


The key typically identifies the resource being rate-limited (e.g., user ID, IP address, API endpoint). The RateLimiter uses this key to track attempts in the cache.

Custom Response Callbacks with response()

The response() method sets a callback that generates a custom response when the rate limit is exceeded:

response(Closure $callback): static

Sources: src/RateLimiting/Limit.php86-91

This callback can be used to customize error responses, log rate limit violations, or implement custom logic:


The responseCallback property is nullable and defaults to null. When set, consumers of the Limit can invoke this callback to generate appropriate responses.

Fluent API Example

The fluent API allows concise, readable rate limit definitions:


Sources: src/RateLimiting/Limit.php76-91

This pattern allows method chaining for clean, expressive rate limit definitions.

Unlimited Limits

The Unlimited class is a special subclass of Limit that represents no rate limiting. It is returned by the Limit::none() factory method:

Limit::none(): Unlimited

Sources: src/RateLimiting/Limit.php68-71

The Unlimited class serves as a marker type that consumers can check to determine whether rate limiting should be enforced. This allows conditional rate limiting where certain users or endpoints may have unlimited access.


Sources: src/RateLimiting/Limit.php68-71

The Unlimited class inherits all properties and methods from Limit but is intended to be detected via type checking rather than through property inspection.

Usage with RateLimiter

The Limit class is designed to be consumed by the RateLimiter class, which enforces the defined limits using the cache subsystem. The typical flow involves:

  1. Defining a Limit: Create a Limit instance using factory methods
  2. Setting Context: Use fluent methods to configure the key and response callback
  3. Consuming the Limit: Pass the Limit to RateLimiter methods for enforcement

Sources: src/RateLimiting/Limit.php1-92

The RateLimiter extracts the key, maxAttempts, and decayMinutes properties from the Limit to perform rate limiting operations. If responseCallback is set, it can be invoked when the limit is exceeded to generate custom responses.

Common Use Cases

The Limit class supports various rate limiting scenarios:

ScenarioConfigurationUse Case
API Rate LimitingLimit::perMinute(60)->by($apiKey)Limit API calls per client
Login AttemptsLimit::perHour(5)->by($ipAddress)Prevent brute force attacks
File UploadsLimit::perDay(100)->by($userId)Control resource usage
Email SendingLimit::perHour(10)->by($userId)Prevent spam
Search QueriesLimit::perMinute(30)->by($sessionId)Limit expensive operations
Admin ActionsLimit::none()Unlimited access for privileged users

Sources: src/RateLimiting/Limit.php1-92

The declarative nature of the Limit class makes it easy to define, test, and maintain rate limiting rules throughout an application.

Named Rate Limiters

The system supports named rate limiter configurations for reusable rate limiting policies:


Sources: src/RateLimiter.php36-49

Named limiters allow centralized configuration of rate limiting policies that can be referenced by name throughout the application.

Cache Store Integration

The rate limiting system works with any cache store implementation through the Factory interface:

Cache OperationUsage in Rate Limiting
add()Initialize counters and timers atomically
increment()Increment attempt counters
get()Retrieve current attempt counts
put()Reset counters when needed
forget()Clear rate limit data
has()Check timer existence

Sources: src/RateLimiter.php94-108 src/RateLimiter.php122 src/RateLimiter.php133

The system leverages atomic operations where available (like Redis INCRBY) and handles race conditions through careful ordering of cache operations.

Utility Methods

The RateLimiter class provides several utility methods for rate limit management:


Sources: src/RateLimiter.php117-123 src/RateLimiter.php139-155 src/RateLimiter.php160-167 src/RateLimiter.php172-178

These utility methods provide comprehensive control over rate limit state, allowing applications to query current status, reset limits, and perform cleanup operations as needed.