- How do I install and configure spatie/guzzle-rate-limiter-middleware in a Laravel app?
- Install it with composer require spatie/guzzle-rate-limiter-middleware, then create a HandlerStack with HandlerStack::create() and push the RateLimiterMiddleware onto it. Pass that stack as the handler option when building your Guzzle client. In Laravel, bind a preconfigured client in a service provider or small factory so every outbound call shares the same throttling configuration.
- Does this rate limiter middleware work with Laravel's Http facade?
- Yes, indirectly. The Http facade is Guzzle underneath, so you can inject a custom handler stack into the facade's client builder. This is a small, well-bounded integration spike rather than an architectural risk, and the package itself has no Laravel dependency, which keeps it usable in shared internal packages.
- Can the rate limiter share limits across multiple PHP-FPM workers or queue workers?
- Not with the default setup. The bundled InMemoryStore only tracks requests inside a single PHP process, which is fine for a CLI script or proof of concept but effectively meaningless behind PHP-FPM or multiple queue workers. To coordinate limits across processes you must implement the Store interface backed by Redis or the Laravel cache.
- Can I set different rate limits per API provider or endpoint?
- The middleware enforces one limit per client instance, so per-endpoint or per-provider limits mean multiple named clients. Build a separate handler stack and store namespace for each provider and expose the limits through config/services.php. This keeps configuration explicit and stops one provider's limit from throttling another.
- Why does my request hang or sleep when the rate limit is reached?
- When the limit is hit the middleware calls sleep until a slot becomes available, so a throttled request occupies a PHP-FPM or queue worker for the entire wait. A 1 request per second limit with a burst of 60 requests can pin a worker for about a minute. Treat this as a capacity concern: cap waits with client timeouts, move large batches to queues, and size limits to your worker pool.
- How do I implement a Redis or Laravel cache store for the rate limiter?
- Implement the Store interface using an atomic operation, such as an increment with a TTL or a lock, rather than the read-modify-write pattern shown in the README. A naive Cache::get, array_merge, and Cache::put sequence can overshoot the limit under concurrency and leaves keys without expiry. Once your store is atomic and namespaced per provider, inject it into the middleware and it works unchanged across workers.
- Does this middleware retry requests that return 429 or 503 responses?
- No. It performs pre-emptive client-side throttling only and does not inspect 429 or 503 responses or back off adaptively. It complements a retry middleware rather than replacing one, so pair it with retries and Retry-After handling for resilient provider integrations.
- Which PHP and Guzzle versions does spatie/guzzle-rate-limiter-middleware support?
- The package requires PHP 8.3 or higher and supports Guzzle 6.3, 7, and 8. Because there is no Laravel dependency, any Laravel version running a supported PHP and Guzzle combination will work. Check the Packagist release notes before upgrading major Guzzle versions.
- How do I test rate-limited HTTP calls without slowing down my test suite?
- Because the middleware sleeps when the limit is hit, real usage in tests can be slow, so swap in a fake or spy store that records hits without waiting. Assert on the recorded requests and on your client configuration rather than on wall-clock behaviour. Keep a separate integration test with a tiny limit if you want to verify the sleeping path itself.
- Is spatie/guzzle-rate-limiter-middleware still maintained and what are the alternatives?
- The package has roughly 170 stars and no dependents, which is thin external validation, but Spatie is a long-standing open source shop and the codebase is small and MIT licensed, so it is forkable in an afternoon. Alternatives include writing a custom Guzzle middleware, using your HTTP client's built-in throttling, or handling limits at the queue or gateway level. For most Laravel teams the deciding factor is whether you need a shared atomic store rather than the limiter itself.