mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
fix: storage preview cache misses and stale cache eviction
Three bugs causing storage preview cache to be ineffective: 1. Cache keys included the `token` auth parameter, so requests using resource tokens always generated unique keys and never hit cache. Introduced `cache.params` label for routes to opt-in specific params into the cache key; preview now declares only the transform params. 2. Cache hits never refreshed `accessedAt` in the DB or the filesystem file mtime, because `$response->send()` in the init hook skips the shutdown hook. After 30 days the maintenance job evicted still-active cache entries, and after the original 30-day filesystem TTL the cache file expired — causing periodic full re-renders. The cache-hit path now updates both on the APP_CACHE_UPDATE (24h) interval. 3. `updateDocument` in the preview action passed the full file document instead of a sparse one when updating `transformedAt`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f371237fd5
commit
f2df9cb93a
@@ -693,6 +693,15 @@ Http::init()
|
||||
}
|
||||
}
|
||||
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), new Document([
|
||||
'accessedAt' => DateTime::now(),
|
||||
])));
|
||||
// Refresh the filesystem file's mtime so TTL-based expiry in cache->load() stays valid
|
||||
$cache->save($key, $data);
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp))
|
||||
->addHeader('X-Appwrite-Cache', 'hit')
|
||||
|
||||
@@ -54,6 +54,7 @@ class Get extends Action
|
||||
->label('cache', true)
|
||||
->label('cache.resourceType', 'bucket/{request.bucketId}')
|
||||
->label('cache.resource', 'file/{request.fileId}')
|
||||
->label('cache.params', ['width', 'height', 'gravity', 'quality', 'borderWidth', 'borderColor', 'borderRadius', 'opacity', 'rotation', 'background', 'output'])
|
||||
->label('sdk', new Method(
|
||||
namespace: 'storage',
|
||||
group: 'files',
|
||||
@@ -277,7 +278,9 @@ class Get extends Action
|
||||
$transformedAt = $file->getAttribute('transformedAt', '');
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
|
||||
$file->setAttribute('transformedAt', DateTime::now());
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), new Document([
|
||||
'transformedAt' => $file->getAttribute('transformedAt'),
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +234,10 @@ class Request extends UtopiaRequest
|
||||
public function cacheIdentifier(): string
|
||||
{
|
||||
$params = $this->getParams();
|
||||
$allowedParams = $this->getRoute()?->getLabel('cache.params', null);
|
||||
if ($allowedParams !== null) {
|
||||
$params = array_intersect_key($params, array_flip($allowedParams));
|
||||
}
|
||||
ksort($params);
|
||||
return md5($this->getURI() . '*' . serialize($params) . '*' . APP_CACHE_BUSTER);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user