PHPackages                             recranet/guzzle-rate-limiter-middleware - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. recranet/guzzle-rate-limiter-middleware

ActiveLibrary[HTTP &amp; Networking](/categories/http)

recranet/guzzle-rate-limiter-middleware
=======================================

Thread-safe Guzzle rate limiter middleware using Symfony RateLimiter

1.0.2(4mo ago)03MITPHPPHP &gt;=8.2

Since Dec 24Pushed 4mo agoCompare

[ Source](https://github.com/recranet/guzzle-rate-limiter-middleware)[ Packagist](https://packagist.org/packages/recranet/guzzle-rate-limiter-middleware)[ RSS](/packages/recranet-guzzle-rate-limiter-middleware/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (6)Versions (4)Used By (0)

Guzzle Rate Limiter Middleware
==============================

[](#guzzle-rate-limiter-middleware)

A thread-safe rate limiter middleware for Guzzle using Symfony RateLimiter with atomic locks.

Features
--------

[](#features)

- Thread-safe rate limiting using distributed locks
- Multiple rate limiting strategies: sliding window and token bucket
- Configurable handlers for rate limit exceeded scenarios
- Works across multiple processes and servers

Why This Package?
-----------------

[](#why-this-package)

Unlike simple in-memory rate limiters, this package uses Symfony's Lock component to provide atomic rate limit checks. This prevents race conditions when multiple workers or processes check limits simultaneously, making it safe for use in distributed systems, queue workers, and multi-threaded applications.

Installation
------------

[](#installation)

```
composer require recranet/guzzle-rate-limiter-middleware
```

Usage
-----

[](#usage)

### Basic Usage

[](#basic-usage)

```
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Recranet\GuzzleRateLimiterMiddleware\RateLimiterMiddleware;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\RedisStore;

$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);

$cache = new RedisAdapter($redis);
$lockFactory = new LockFactory(new RedisStore($redis));

$stack = HandlerStack::create();
$stack->push(RateLimiterMiddleware::perSecond(5, $cache, $lockFactory, 'api-client'));

$client = new Client([
    'handler' => $stack,
]);
```

### Factory Methods

[](#factory-methods)

The middleware provides several factory methods for common rate limiting scenarios:

```
// 5 requests per second
RateLimiterMiddleware::perSecond(5, $cache, $lockFactory, 'api-client');

// 100 requests per minute
RateLimiterMiddleware::perMinute(100, $cache, $lockFactory, 'api-client');

// 10 requests per 30 seconds
RateLimiterMiddleware::perXSeconds(30, 10, $cache, $lockFactory, 'api-client');

// 1000 requests per 15 minutes
RateLimiterMiddleware::perXMinutes(15, 1000, $cache, $lockFactory, 'api-client');
```

### Token Bucket

[](#token-bucket)

For APIs that allow bursting, use the token bucket strategy:

```
// Sustained rate of 1 request per 5 seconds, with burst capacity of 3
RateLimiterMiddleware::tokenBucket(
    rate: '5 seconds',
    burst: 3,
    cache: $cache,
    lockFactory: $lockFactory,
    id: 'api-client',
);
```

Handlers
--------

[](#handlers)

When the rate limit is exceeded, a handler determines what happens next.

### SleepHandler (Default)

[](#sleephandler-default)

Blocks the process until the rate limit window resets, then retries automatically:

```
use Recranet\GuzzleRateLimiterMiddleware\Handler\SleepHandler;

$handler = new SleepHandler(
    min: 0,         // Minimum delay in ms
    max: 300000,    // Maximum delay in ms (5 minutes)
);

RateLimiterMiddleware::perSecond(5, $cache, $lockFactory, 'api-client', $handler);
```

### ThrowExceptionHandler

[](#throwexceptionhandler)

Throws a `RateLimitException` for the calling code to handle:

```
use Recranet\GuzzleRateLimiterMiddleware\Handler\ThrowExceptionHandler;
use Recranet\GuzzleRateLimiterMiddleware\Exception\RateLimitException;

$handler = new ThrowExceptionHandler(
    min: 0,
    max: 300000,
);

$middleware = RateLimiterMiddleware::perSecond(5, $cache, $lockFactory, 'api-client', $handler);

try {
    $response = $client->get('/api/endpoint');
} catch (RateLimitException $e) {
    $retryAfterMs = $e->getRetryDelay();
    // Handle accordingly, e.g., requeue with delay
}
```

This is useful for message queue systems where you want to requeue the job with a delay rather than blocking the worker.

### Custom Handler

[](#custom-handler)

Implement `RateLimitExceededHandler` to create your own handler:

```
use Psr\Http\Message\RequestInterface;
use Recranet\GuzzleRateLimiterMiddleware\Handler\RateLimitExceededHandler;

class LogAndSleepHandler implements RateLimitExceededHandler
{
    public function __construct(
        private LoggerInterface $logger,
    ) {
    }

    public function handle(int $waitMs, RequestInterface $request, array $options, callable $nextHandler): mixed
    {
        $this->logger->warning('Rate limit exceeded', [
            'wait_ms' => $waitMs,
            'uri' => (string) $request->getUri(),
        ]);

        usleep($waitMs * 1000);

        return null; // Return null to retry
    }
}
```

Cache Backends
--------------

[](#cache-backends)

Any PSR-6 cache implementation works. Here are some common options:

### Redis (Recommended for distributed systems)

[](#redis-recommended-for-distributed-systems)

```
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Lock\Store\RedisStore;

$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);

$cache = new RedisAdapter($redis);
$lockFactory = new LockFactory(new RedisStore($redis));
```

### Filesystem (Single server)

[](#filesystem-single-server)

```
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Lock\Store\FlockStore;

$cache = new FilesystemAdapter();
$lockFactory = new LockFactory(new FlockStore());
```

### APCu (Single server, high performance)

[](#apcu-single-server-high-performance)

```
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Lock\Store\SemaphoreStore;

$cache = new ApcuAdapter();
$lockFactory = new LockFactory(new SemaphoreStore());
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance74

Regular maintenance activity

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

139d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/bdd6d6951efb85c875a00f2ff0e04c4be6bfc2d5943d37cdafd510cd68d3878b?d=identicon)[recranet](/maintainers/recranet)

---

Top Contributors

[![mikepage](https://avatars.githubusercontent.com/u/17899539?v=4)](https://github.com/mikepage "mikepage (15 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/recranet-guzzle-rate-limiter-middleware/health.svg)

```
[![Health](https://phpackages.com/badges/recranet-guzzle-rate-limiter-middleware/health.svg)](https://phpackages.com/packages/recranet-guzzle-rate-limiter-middleware)
```

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[spatie/crawler

Crawl all internal links found on a website

2.8k16.3M52](/packages/spatie-crawler)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)[ec-cube/ec-cube

EC-CUBE EC open platform.

78527.0k1](/packages/ec-cube-ec-cube)[api-platform/metadata

API Resource-oriented metadata attributes and factories

223.5M96](/packages/api-platform-metadata)[muhammadhuzaifa/telescope-guzzle-watcher

Telescope Guzzle Watcher provide a custom watcher for intercepting http requests made via guzzlehttp/guzzle php library. The package uses the on\_stats request option for extracting the request/response data. The watcher intercept and log the request into the Laravel Telescope HTTP Client Watcher.

98239.8k1](/packages/muhammadhuzaifa-telescope-guzzle-watcher)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
