From af9e4d0c99d9121e63097dca91900c2ad6fc977e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Ho=CC=88=C3=9Fl?= Date: Sat, 21 Dec 2024 18:41:24 +0100 Subject: [PATCH] Begin background cache rebuild --- components/HashedStaticCache.php | 51 +++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/components/HashedStaticCache.php b/components/HashedStaticCache.php index dc2efe442f..1e6afe7d31 100644 --- a/components/HashedStaticCache.php +++ b/components/HashedStaticCache.php @@ -4,6 +4,7 @@ namespace app\components; +use app\models\backgroundJobs\IBackgroundJob; use app\models\settings\AntragsgruenApp; class HashedStaticCache @@ -17,6 +18,8 @@ class HashedStaticCache private bool $skipCache = false; private ?int $timeout = null; + private ?IBackgroundJob $rebuildBackgroundJob = null; + public function __construct(string $functionName, ?array $dependencies) { $this->functionName = $functionName; @@ -53,6 +56,13 @@ public function setIsBulky(bool $isBulky): self return $this; } + public function setRebuildBackgroundJob(IBackgroundJob $rebuildBackgroundJob): self + { + $this->rebuildBackgroundJob = $rebuildBackgroundJob; + + return $this; + } + /** * Setting a cache to synchronized prevents the system from generating the same cache in parallel. * This does come with some performance impact due to the communication with Redis / File system, @@ -84,13 +94,13 @@ public function getCacheKey(): string return $this->cacheKey; } - public function getCached(callable $method): mixed + public function getCached(callable $method, ?callable $cacheOutdatedDecorator = null): mixed { if (!$this->skipCache) { // Hint: don't even try to aquire a lock if a cache item already exists $cached = $this->getCache(); if ($cached !== false) { - return $cached; + return $this->returnDecoratedCache($cached, $cacheOutdatedDecorator); } } @@ -101,9 +111,11 @@ public function getCached(callable $method): mixed $cached = $this->getCache(); if ($cached !== false) { ResourceLock::unlockCache($this); - return $cached; + return $this->returnDecoratedCache($cached, $cacheOutdatedDecorator); } + // @TODO call backgroundjob if set + $result = $method(); ResourceLock::unlockCache($this); } else { @@ -122,19 +134,43 @@ private static function getDirectory(string $key): string { } /** - * @return mixed|false + * @param array{content: mixed, createdAtTs: int|null} $cache + */ + private function returnDecoratedCache(array $cache, ?callable $cacheOutdatedDecorator): mixed + { + $content = $cache['content']; + if ($cacheOutdatedDecorator) { + $content = $cacheOutdatedDecorator($cache['content'], $cache['createdAtTs']); + } + return $content; + } + + /** + * @return array{content: mixed, createdAtTs: int|null}|false */ - private function getCache(): mixed + private function getCache(): array|false { if ($this->isBulky && AntragsgruenApp::getInstance()->viewCacheFilePath) { $directory = self::getDirectory($this->cacheKey); if (file_exists($directory . '/' . $this->cacheKey)) { - return (string)file_get_contents($directory . '/' . $this->cacheKey); + $mtime = filemtime($directory . '/' . $this->cacheKey); + return [ + 'content' => (string)file_get_contents($directory . '/' . $this->cacheKey), + 'createdAtTs' => ($mtime ? $mtime : null), + ]; } else { return false; } } else { - return \Yii::$app->cache->get($this->cacheKey); + $content = \Yii::$app->cache->get($this->cacheKey); + if ($content === false) { + return false; + } else { + return [ + 'content' => $content, + 'createdAtTs' => null, + ]; + } } } @@ -165,6 +201,7 @@ public function setCache(mixed $data): void public function flushCache(): void { if ($this->isBulky && AntragsgruenApp::getInstance()->viewCacheFilePath) { + // @TODO Trigger backgroundjob instead if set $directory = self::getDirectory($this->cacheKey); if (file_exists($directory . '/' . $this->cacheKey)) { unlink($directory . '/' . $this->cacheKey);