Skip to content

Instantly share code, notes, and snippets.

@garyblankenship
Last active June 23, 2025 16:08
Show Gist options
  • Save garyblankenship/70cf6ac2763f4e1a181ea5b201547bef to your computer and use it in GitHub Desktop.
Save garyblankenship/70cf6ac2763f4e1a181ea5b201547bef to your computer and use it in GitHub Desktop.
Laravel Cache::grace() return stale and dispatch revalidate #php
<?php
/**
* Graceful cache retrieval and updating macro.
*
* First, tries to retrieve the cached value. If not found, uses a grace value.
* Schedules a background job for updating the cache if grace value is found.
*
* @param string $key The cache key to retrieve.
* @param int $ttl Time to live for the cache, in seconds.
* @param callable $callback Function to call for generating cache value.
* @return mixed The cached data or fresh data from the callback.
*
* Pseudocode:
* 1. Attempt to retrieve the value from the cache using the provided key.
* - If the value exists, return it.
* 2. If the value is not in the cache, attempt to retrieve the grace value.
* 3. If the grace value exists:
* - Schedule a background job to update the main cache value using the callback.
* - Return the grace value.
* 4. If the grace value does not exist:
* - Execute the callback to generate a new value.
* - Return the new value.
*
* Usage Example:
* Suppose you want to cache user data and refresh it every 10 minutes. You can use the 'grace' macro like this:
*
* $userData = Cache::grace('user_'. $userId, 600, function () use ($userId) {
* // Code to fetch user data from database or external service
* return User::find($userId);
* });
*
* This will try to get 'user_$userId' from the cache. If it's not found, it will try to use the grace value.
* If neither is available, it will fetch the user data using the provided callback and cache it for future requests.
*/
Cache::macro('grace', function ($key, $ttl, $callback) {
// Attempt to retrieve the cached value for the given key.
$value = Cache::get($key);
// If the cached value exists, return it immediately.
if ($value !== null) {
return $value;
}
// Retrieve a fallback value (grace value) from the cache.
$graceValue = Cache::get('grace.'.$key);
// If grace value exists, schedule a background job to refresh the cache.
if ($graceValue !== null) {
// The cache will be updated after the response is sent to the user.
// App::terminating(fn () => Cache::put($key, $callback(), $ttl));
dispatch(function () use ($key, $ttl, $callback) {
Cache::put($key, $callback(), $ttl);
Cache::put('grace.'.$key, $callback(), $ttl * 2);
});
}
// Return the grace value or, if not present, execute the callback for a fresh result.
return $graceValue ?? $callback();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment