className; $method = $proceedingJoinPoint->methodName; $arguments = $proceedingJoinPoint->arguments['keys']; $now = time(); /** * @var CacheAhead $annotation */ [$key, $ttl, $group, $annotation] = $this->annotationManager->getCacheAheadValue($className, $method, $arguments); $driver = $this->manager->getDriver($group); $callback = static function () use ($proceedingJoinPoint, $driver, $annotation, $key, $now, $ttl) { $result = $proceedingJoinPoint->process(); if (! in_array($result, (array) $annotation->skipCacheResults, true)) { $driver->set( $key, [ 'expired_time' => $now + $ttl - $annotation->aheadSeconds, 'data' => $result, ], $ttl ); if ($driver instanceof KeyCollectorInterface && $annotation instanceof CacheAhead && $annotation->collect) { $driver->addKey($annotation->prefix . 'MEMBERS', $key); } } return $result; }; [$has, $result] = $driver->fetch($key); // If the cache exists, return it directly. if ($has && isset($result['expired_time'], $result['data'])) { if ( $now > $result['expired_time'] && $driver->getConnection()->set($key . ':lock', '1', ['NX', 'EX' => $annotation->lockSeconds]) ) { // If the cache is about to expire, refresh the cache. Coroutine::create($callback); } return $result['data']; } // If the cache does not exist, execute the callback and cache the result. if ($annotation->runAsync) { Coroutine::create($callback); return null; } return $callback(); } }