Download the PHP package kyzegs/guzzle-rate-limit-middleware without Composer
On this page you can find all versions of the php package kyzegs/guzzle-rate-limit-middleware. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download kyzegs/guzzle-rate-limit-middleware
More information about kyzegs/guzzle-rate-limit-middleware
Files in kyzegs/guzzle-rate-limit-middleware
Package guzzle-rate-limit-middleware
Short Description A configurable Guzzle middleware for rate limiting HTTP requests based on response headers
License MIT
Informations about the package guzzle-rate-limit-middleware
Guzzle Rate Limit Middleware
A configurable Guzzle middleware that prevents your application from hitting 429 Too Many Requests by reading rate-limit response headers and delaying requests before they exceed the limit.
State is persisted through a pluggable store, so rate limiting works across separate requests and processes โ not just within a single operation.
Features
- ๐ง Configurable headers โ works with any API (Discord, GitHub, Twitter, the IETF
RateLimit-*draft, or your own). - ๐พ Cross-process state โ share rate-limit state via PSR-16 (Redis, Memcached, Laravel/Symfony cache), the filesystem, or in-memory.
- โณ Pre-emptive delays โ sleeps until a bucket resets instead of failing.
- ๐ 429 retries โ honours
Retry-Afterand retries up to a configurable limit, then optionally throws. - ๐ชฃ Bucket-hash discovery โ adapts to APIs (like Discord) that assign buckets dynamically.
- ๐ Optional locking โ plug in a distributed lock to serialise concurrent callers.
- ๐งช Fully testable โ the clock and sleeper are injectable, so timing is deterministic in tests.
Installation
Requires PHP 8.2+ and Guzzle 7.10+.
Quick start
The default middleware reads the standard X-RateLimit-* headers and keeps state in memory.
Per-API presets
The Discord preset also enables a cross-process 50 request/second global
budget, isolates all state by a one-way authorization fingerprint, accepts the
JSON retry_after fallback, and stops at 9,000 invalid requests per 10 minutes
before Discord's Cloudflare threshold. These values are configurable through
Options:
Raw authorization and webhook tokens never appear in persisted bucket or lock keys. Interaction callback endpoints are excluded from Discord's bot-global budget. Shared-scope 429 responses do not consume the invalid-request budget.
Cross-process rate limiting
To rate limit across separate requests/processes, give the middleware a persistent store. The recommended option is any PSR-16 cache:
Or use the zero-dependency filesystem store:
Available stores
| Store | Cross-process | Notes |
|---|---|---|
InMemoryStore (default) |
โ | Lives for the PHP process only. Good for one long-running worker and tests. |
FilesystemStore |
โ | JSON files with atomic writes. No extra dependencies. |
Psr16Store |
โ | Wraps any Psr\SimpleCache\CacheInterface โ Redis, Memcached, Laravel, Symfony, โฆ |
Custom headers
Header names live in the Headers config object:
reset values below the year-2000 epoch are treated as relative seconds; larger values as absolute UNIX timestamps.
Behaviour options
When retries are exhausted on a 429 and throwOnRateLimit is true, a
Kyzegs\GuzzleRateLimitMiddleware\Exception\RateLimitExceededException is thrown
(carrying the request, response, retry-after seconds and global flag).
Bucket resolution
Requests are grouped into buckets that share a rate limit. The default
DefaultBucketResolver keys by METHOD host /path and collapses
identifier-like path segments โ numeric ids/snowflakes, UUIDs, and long hex
tokens โ to {id} (so /users/1 and /users/2, or two UUIDs, share a bucket).
Human-readable slugs (e.g. /repos/{owner}/{repo}) are left literal because
they're indistinguishable from route words; provide a custom resolver for APIs
that bucket on such segments.
Provide your own by implementing BucketResolverInterface:
Bucket-hash discovery (Discord)
Some APIs assign a request to a bucket dynamically and report it via a header
(Discord's X-RateLimit-Bucket). When Headers::$bucket is set, the middleware
stores state under the discovered bucket and re-keys automatically if the API
reassigns a route. RateLimitMiddleware::discord() enables this together with a
DiscordBucketResolver that respects Discord's major parameters
(channel_id, guild_id, webhook_id and webhook_token).
Concurrency / locking
By default there is no locking. To serialise concurrent callers that share a
bucket (e.g. multiple workers), implement LockFactoryInterface/LockInterface
and pass the factory:
Testing your integration
The clock and sleeper are injectable, so you can assert delays without real
waits. See tests/ โ FakeClock and RecordingSleeper are good starting points.
Development
License
MIT License. See LICENSE.
All versions of guzzle-rate-limit-middleware with dependencies
guzzlehttp/guzzle Version ^7.10
psr/log Version ^3.0
psr/simple-cache Version ^3.0