Installation Add the package via Composer:
composer require edsi-tech/redis-guzzle-cache:~0.2
Redis Connection
Ensure you have a Redis connection configured in Laravel (e.g., redis in config/database.php). Inject it via the service container:
$redis = app('redis');
Basic Usage Attach the cache subscriber to a Guzzle client:
use GuzzleHttp\Cache\CacheSubscriber;
use GuzzleHttp\Client;
use EDSI\RedisGuzzleCache\CacheStorage;
$client = new Client();
CacheSubscriber::attach($client, [
'storage' => new CacheStorage(new \EDSI\RedisGuzzleCache\RedisGuzzleCache($redis, 'guzzle_cache_'))
]);
First Use Case Cache HTTP responses for a GET request:
$response = $client->get('https://api.example.com/data');
// Subsequent identical requests will use cached responses.
Request Caching Use the subscriber to cache responses automatically for idempotent requests (GET, HEAD, etc.):
$client->get('https://api.example.com/users', [
'cache' => [
'etag' => true, // Enable ETag-based caching
'private' => false, // Cache for all users
]
]);
Cache Key Customization Override the default key generation (e.g., for API versioning):
CacheSubscriber::attach($client, [
'storage' => new CacheStorage(new RedisGuzzleCache($redis, 'v2_guzzle_cache_')),
'cache_key' => function ($request) {
return 'custom_key_' . md5($request->getUri());
}
]);
Conditional Caching Disable caching for specific routes or headers:
$client->get('https://api.example.com/uncached', [
'cache' => ['etag' => false]
]);
Cache Invalidation Manually clear cached responses for a key prefix:
$redis->flushDb(); // Aggressive (clears all keys)
// OR
$redis->keys('guzzle_cache_*')->each(function ($key) {
$redis->del($key);
});
Laravel Service Provider
Register the client globally in AppServiceProvider:
public function register()
{
$this->app->singleton('guzzle.cache.client', function ($app) {
$client = new Client();
CacheSubscriber::attach($client, [
'storage' => new CacheStorage(new RedisGuzzleCache($app['redis'], 'guzzle_cache_'))
]);
return $client;
});
}
Middleware for Caching Use Guzzle middleware to extend caching logic:
use GuzzleHttp\Middleware;
$stack = Middleware::tap(function ($request) {
// Pre-request logic (e.g., add headers)
});
$client = new Client(['handler' => HandlerStack::create($stack)]);
Key Collisions
guzzle_cache_ by default) to Redis keys. Ensure this doesn’t conflict with other cached data in the same Redis instance.app_guzzle_cache_).TTL Misconfiguration
CacheStorage is properly configured:
CacheSubscriber::attach($client, [
'storage' => new CacheStorage(new RedisGuzzleCache($redis, 'guzzle_cache_'), 3600) // 1-hour TTL
]);
Redis Connection Issues
try {
$response = $client->get('https://api.example.com/data');
} catch (\RedisException $e) {
// Fallback to non-cached request or log the error
$response = $client->get('https://api.example.com/data', ['cache' => ['etag' => false]]);
}
Memory Bloat
redis-cli --scan --pattern "guzzle_cache_*"
RedisGuzzleCache with a TTL or implement a cleanup cron job.Thread Safety
Package Abandonment
Inspect Cached Keys Dump Redis keys to verify caching:
$keys = $redis->keys('guzzle_cache_*');
dd($keys);
Disable Caching Temporarily Override the subscriber to bypass caching for debugging:
CacheSubscriber::attach($client, [
'storage' => new CacheStorage(new \EDSI\RedisGuzzleCache\NullCache()) // Mock storage
]);
Log Cache Hits/Misses Extend the subscriber to log cache behavior:
CacheSubscriber::attach($client, [
'on_cache_hit' => function ($response) {
Log::debug('Cache hit for: ' . $response->getEffectiveUri());
},
'on_cache_miss' => function ($request) {
Log::debug('Cache miss for: ' . $request->getUri());
}
]);
Custom Storage Adapter
Implement GuzzleHttp\Cache\Storage\StorageInterface to replace Redis:
class CustomCacheStorage implements StorageInterface {
public function fetch($key) { /* ... */ }
public function save($key, $value, $ttl) { /* ... */ }
public function delete($key) { /* ... */ }
}
Key Transformation
Modify the key generation logic in RedisGuzzleCache:
class CustomRedisGuzzleCache extends RedisGuzzleCache {
protected function generateKey($request) {
return 'custom_' . parent::generateKey($request);
}
}
Compression Compress cached responses to save Redis memory:
use GuzzleHttp\Stream\StreamInterface;
class CompressedCacheStorage implements StorageInterface {
public function save($key, StreamInterface $value, $ttl) {
$compressed = gzcompress($value->getContents());
$redis->set($key, $compressed, $ttl);
}
}
Fallback Cache Combine with Laravel’s cache (e.g., file/APCu) for redundancy:
use Illuminate\Cache\CacheManager;
$fallback = app('cache')->store('file');
$storage = new CacheStorage(new RedisGuzzleCache($redis, 'guzzle_cache_'), 3600, $fallback);
How can I help you explore Laravel packages today?