Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rate Limiter Laravel Package

symfony/rate-limiter

Symfony Rate Limiter provides token bucket rate limiting for your app. Create limiters with RateLimiterFactory and a storage backend (e.g., in-memory), then reserve tokens with blocking waits or consume instantly to allow/skip work based on availability.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup in Laravel (Updated for v8.1.0-BETA3)
1. **Install the package** (unchanged):
   ```bash
   composer require symfony/rate-limiter
  1. Configure a basic rate limiter (updated for v8.1.0-BETA3):

    // config/rate_limits.php
    return [
        'login_attempts' => [
            'policy' => 'token_bucket',
            'limit' => 5,
            'rate' => ['interval' => '5 minutes'],
            'reservation_ttl' => '1 hour',
            'window_mode' => 'calendar_aligned', // New: Calendar-aligned fixed window mode
        ],
        'api_calls' => [
            'policy' => 'sliding_window',
            'limit' => 100,
            'rate' => ['interval' => '1 minute'],
            'grace_period' => 5,
            'window_mode' => 'calendar_aligned', // New: Calendar-aligned fixed window mode
        ],
    ];
    
  2. Service Provider Update (now leverages v8.1.0-BETA3's hardened window mode):

    // app/Providers/RateLimiterServiceProvider.php
    use Symfony\Component\RateLimiter\RateLimiterFactory;
    use Symfony\Component\RateLimiter\Storage\RedisStorage;
    use Symfony\Component\RateLimiter\Policy\SlidingWindowPolicy;
    use Symfony\Component\RateLimiter\Policy\FixedWindowPolicy;
    
    class RateLimiterServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton('rate_limiter.storage', function () {
                return new RedisStorage($this->app['redis']);
            });
    
            $this->app->bind('rate_limiter.factory', function ($app) {
                return new RateLimiterFactory(
                    config('rate_limits'),
                    $app['rate_limiter.storage'],
                    $app['config']['rate_limits.default_policy'] ?? 'token_bucket'
                );
            });
        }
    
        public function boot()
        {
            // Register new policy types with hardened window mode
            RateLimiterFactory::addPolicy('sliding_window', function ($config) {
                return new SlidingWindowPolicy(
                    $config['limit'],
                    $config['rate']['interval'],
                    $config['grace_period'] ?? 0
                );
            });
    
            RateLimiterFactory::addPolicy('fixed_window', function ($config) {
                return new FixedWindowPolicy(
                    $config['limit'],
                    $config['rate']['interval'],
                    $config['window_mode'] ?? 'fixed' // Default to 'fixed' for backward compatibility
                );
            });
        }
    }
    
  3. Critical Update for Window Mode Handling (v8.1.0-BETA3 improvements):

    // Updated middleware with calendar-aligned window mode support
    public function handle($request, Closure $next)
    {
        $limiter = app('rate_limiter.factory')->create([
            'id' => 'login_' . $request->ip(),
            'policy' => config('rate_limits.login_attempts.policy'),
            'limit' => config('rate_limits.login_attempts.limit'),
            'rate' => config('rate_limits.login_attempts.rate'),
            'reservation_ttl' => config('rate_limits.login_attempts.reservation_ttl'),
            'window_mode' => config('rate_limits.login_attempts.window_mode') ?? 'fixed',
        ]);
    
        $consumption = $limiter->consume(1);
        if (!$consumption->isAccepted()) {
            return response()->json(['error' => 'Too many attempts'], 429)
                ->header('Retry-After', $consumption->getRetryAfter()->format('U'))
                ->header('X-RateLimit-Reservations', $limiter->getPendingReservations());
        }
    
        return $next($request);
    }
    

First Use Case: Secure API Endpoints (Updated for v8.1.0-BETA3)

// Example: Payment endpoint with calendar-aligned window mode
public function processPayment(Request $request)
{
    $limiter = app('rate_limiter.factory')->create([
        'id' => 'payment_' . auth()->id(),
        'policy' => 'fixed_window',
        'limit' => 3,
        'rate' => ['interval' => '1 hour'],
        'window_mode' => 'calendar_aligned', // New hardened mode
    ]);

    $consumption = $limiter->consume(1);
    if (!$consumption->isAccepted()) {
        return response()->json([
            'error' => 'Rate limit exceeded',
            'remaining' => $limiter->getRemainingTokens(),
            'reserved' => $limiter->getPendingReservations(),
            'window_mode' => $limiter->getWindowMode() // New: Expose window mode
        ], 429)
        ->header('Retry-After', $consumption->getRetryAfter()->format('U'));
    }

    // Process payment...
}

Key Starting Points (Updated for v8.1.0-BETA3)

  • Documentation: Symfony RateLimiter v8.1.0-BETA3
  • New Features:
    • Calendar-Aligned Fixed Window Mode: Hardened fixed window mode to align with calendar boundaries (e.g., hour boundaries at :00 minutes)
    • Window Mode Configuration: New window_mode option for fixed_window policy
    • Backward Compatibility: Defaults to fixed window mode if not specified
  • Storage Options: RedisStorage (recommended), InMemoryStorage (dev), DatabaseStorage (custom)
  • Policies:
    • token_bucket (default, improved reservation handling)
    • fixed_window (now supports calendar_aligned mode)
    • sliding_window (with grace period support)

Implementation Patterns

1. Middleware Integration with Calendar-Aligned Windows

// app/Http/Middleware/RateLimitMiddleware.php
public function handle($request, Closure $next, $key = null)
{
    $key = $key ?? $this->resolveRateLimiterKey($request);
    $config = config("rate_limits.{$key}");

    $limiter = app('rate_limiter.factory')->create([
        'id' => $key,
        'policy' => $config['policy'],
        'limit' => $config['limit'],
        'rate' => $config['rate'],
        'reservation_ttl' => $config['reservation_ttl'] ?? null,
        'window_mode' => $config['window_mode'] ?? 'fixed',
    ]);

    $consumption = $limiter->consume(1);
    if (!$consumption->isAccepted()) {
        return response()->json([
            'error' => 'Rate limit exceeded',
            'limit' => $limiter->getLimit(),
            'remaining' => $limiter->getRemainingTokens(),
            'reserved' => $limiter->getPendingReservations(),
            'window_mode' => $limiter->getWindowMode(),
            'next_window' => $limiter->getNextWindowStart()->format('c'),
        ], 429)
        ->header('Retry-After', $consumption->getRetryAfter()->format('U'));
    }

    return $next($request);
}

2. Dynamic Rate Limiting with Calendar-Aligned Windows

// Updated to use calendar-aligned fixed window
$limiter = app('rate_limiter.factory')->create([
    'id' => 'user_' . auth()->id(),
    'policy' => 'fixed_window',
    'limit' => 10,
    'rate' => ['interval' => '1 hour'],
    'window_mode' => 'calendar_aligned', // Aligns to :00 minutes
]);

// New behavior: Windows reset at calendar boundaries (e.g., 1:00 PM instead of 1:00:00.000 PM)
$consumption = $limiter->consume(1);
if (!$consumption->isAccepted()) {
    // Handle rate limit with precise window info
    $nextWindow = $limiter->getNextWindowStart();
    // ...
}

3. Background Job Processing with Window Mode Awareness

// app/Jobs/ProcessBatch.php
public function handle()
{
    $limiter = app('rate_limiter.factory')->create([
        'id' => 'batch_' . $this->batchId,
        'policy' => 'fixed_window',
        'limit' => 100,
        'rate' => ['interval' => '1 day'],
        'window_mode' => 'calendar_aligned', // Aligns to midnight
        'reservation_ttl' => '2 hours',
    ]);

    // Check window alignment before processing
    $currentWindowStart = $limiter->getCurrentWindowStart();
    $nextWindowStart = $limiter->getNextWindowStart();

    // Reserve tokens with explicit TTL
    $reservation = $lim
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope