bedrockstreaming/stale-cache-bundle
Install the Bundle:
composer require bedrockstreaming/stale-cache-bundle
Add to config/bundles.php:
return [
// ...
Bedrock\StaleCacheBundle\BedrockStaleCacheBundle::class => ['all' => true],
];
Configure a Stale Cache Service (config/packages/bedrock_stale_cache.yaml):
bedrock_stale_cache:
decorated_cache_pools:
app.stale_cache: # Service ID for your stale cache
cache_pool: cache.app # Underlying cache pool (e.g., Symfony's default)
max_stale: 3600 # Stale period in seconds (1 hour)
First Use Case: Replace a cache service dependency in your controller/service with the new stale cache:
use Symfony\Contracts\Cache\CacheInterface;
public function __construct(
private CacheInterface $staleCache // Inject 'app.stale_cache'
) {}
Tag-Aware Caching:
If your cache implements TagAwareCacheInterface, leverage it for invalidation:
$this->staleCache->deleteTag('product_123');
Graceful Degradation: Use stale cache for non-critical data (e.g., product listings, user profiles) where stale data is acceptable temporarily.
Layered Caching:
Combine with Symfony’s cache pools (e.g., cache.app for primary storage, app.stale_cache for fallback):
# config/packages/cache.yaml
framework:
cache:
pools:
app.stale_cache: ~ # Auto-configured by the bundle
Dependency Injection: Prefer constructor injection for stale cache services to ensure consistency:
public function __construct(
private CacheInterface $staleCache,
private CacheInterface $fallbackCache
) {}
Contextual Stale Logic:
Override get() to conditionally use stale cache based on runtime logic:
$item = $this->staleCache->get('key', function() {
return $this->fetchExpensiveData();
}, 3600); // TTL
Error Handling:
Bedrock\StaleCacheBundle\Exception\UnavailableResultException trigger stale fallback.src/Exception/UnavailableResultException.php for reference).Debugging:
enable_debug_logs: true to trace stale cache hits/misses and regeneration failures.debug channel; filter with:
bin/console debug:logs --channel=debug | grep StaleCache
Configuration Quirks:
max_stale setting extends the TTL, not replaces it. Example:
max_stale: 3600s → Item is stale after 300s but usable until 3900s total.Performance:
bin/console debug:cache
Custom Exceptions:
Extend UnavailableResultException for domain-specific errors:
class DatabaseUnavailableException extends UnavailableResultException {}
Regeneration Hooks:
Override the bundle’s StaleCacheItem to inject custom logic:
// src/StaleCache/StaleCacheItem.php
class CustomStaleCacheItem extends \Bedrock\StaleCacheBundle\StaleCache\StaleCacheItem {
protected function regenerate(): mixed {
// Custom logic here
return parent::regenerate();
}
}
Dynamic Stale Periods: Use a closure in config (requires custom bundle extension):
max_stale: "%kernel.debug% ? 60 : 3600" # Debug mode = 1m, prod = 1h
Testing: Mock the stale cache in tests to verify fallback behavior:
$this->staleCache->shouldReceive('get')
->once()
->andThrow(new UnavailableResultException('Test failure'));
How can I help you explore Laravel packages today?