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

Redis Guzzle Cache Laravel Package

edsi-tech/redis-guzzle-cache

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the package via Composer:

    composer require edsi-tech/redis-guzzle-cache:~0.2
    
  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');
    
  3. 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_'))
    ]);
    
  4. 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.
    

Implementation Patterns

Workflow Integration

  1. 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
        ]
    ]);
    
  2. 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());
        }
    ]);
    
  3. Conditional Caching Disable caching for specific routes or headers:

    $client->get('https://api.example.com/uncached', [
        'cache' => ['etag' => false]
    ]);
    
  4. 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);
    });
    
  5. 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;
        });
    }
    
  6. 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)]);
    

Gotchas and Tips

Pitfalls

  1. Key Collisions

    • The package prepends a prefix (guzzle_cache_ by default) to Redis keys. Ensure this doesn’t conflict with other cached data in the same Redis instance.
    • Fix: Use a unique prefix (e.g., app_guzzle_cache_).
  2. TTL Misconfiguration

    • The package does not automatically set TTLs for cached responses. Guzzle’s default cache subscriber handles this, but ensure your CacheStorage is properly configured:
      CacheSubscriber::attach($client, [
          'storage' => new CacheStorage(new RedisGuzzleCache($redis, 'guzzle_cache_'), 3600) // 1-hour TTL
      ]);
      
  3. Redis Connection Issues

    • If Redis is down, Guzzle will throw exceptions. Handle this gracefully:
      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]]);
      }
      
  4. Memory Bloat

    • Unbounded caching can fill Redis memory. Monitor key growth:
      redis-cli --scan --pattern "guzzle_cache_*"
      
    • Tip: Use RedisGuzzleCache with a TTL or implement a cleanup cron job.
  5. Thread Safety

    • Redis is thread-safe, but ensure your Laravel app isn’t spawning multiple Guzzle clients with overlapping cache keys unintentionally.
  6. Package Abandonment

    • The package is unmaintained (last release: 2015). Test thoroughly and consider forking if critical bugs arise.

Debugging Tips

  1. Inspect Cached Keys Dump Redis keys to verify caching:

    $keys = $redis->keys('guzzle_cache_*');
    dd($keys);
    
  2. Disable Caching Temporarily Override the subscriber to bypass caching for debugging:

    CacheSubscriber::attach($client, [
        'storage' => new CacheStorage(new \EDSI\RedisGuzzleCache\NullCache()) // Mock storage
    ]);
    
  3. 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());
        }
    ]);
    

Extension Points

  1. 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) { /* ... */ }
    }
    
  2. Key Transformation Modify the key generation logic in RedisGuzzleCache:

    class CustomRedisGuzzleCache extends RedisGuzzleCache {
        protected function generateKey($request) {
            return 'custom_' . parent::generateKey($request);
        }
    }
    
  3. 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);
        }
    }
    
  4. 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);
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky