Skip to content

Commit 366b9cd

Browse files
authored
Fix cache max age. (#671)
1 parent 18ad769 commit 366b9cd

2 files changed

Lines changed: 46 additions & 19 deletions

File tree

graphql.services.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ services:
4747
- '@cache_contexts_manager'
4848
- '@plugin.manager.graphql.schema'
4949
- '@cache.graphql.results'
50+
- '@request_stack'
5051

5152
# Query map provider using the composite pattern.
5253
graphql.query_provider:

src/GraphQL/Execution/QueryProcessor.php

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
namespace Drupal\graphql\GraphQL\Execution;
44

5-
use Drupal\Core\Cache\CacheableDependencyInterface;
5+
use Drupal\Core\Cache\Cache;
66
use Drupal\Core\Cache\CacheableMetadata;
77
use Drupal\Core\Cache\CacheBackendInterface;
88
use Drupal\Core\Cache\Context\CacheContextsManager;
9-
use Drupal\Core\Session\AccountProxyInterface;
109
use Drupal\graphql\Plugin\SchemaPluginManager;
11-
use Drupal\graphql\GraphQL\QueryProvider\QueryProviderInterface;
1210
use Drupal\graphql\GraphQL\Cache\CacheableRequestError;
1311
use GraphQL\Error\Error;
1412
use GraphQL\Error\FormattedError;
@@ -26,9 +24,9 @@
2624
use GraphQL\Utils\AST;
2725
use GraphQL\Utils\TypeInfo;
2826
use GraphQL\Utils\Utils;
29-
use GraphQL\Validator\DocumentValidator;
3027
use GraphQL\Validator\Rules\AbstractValidationRule;
3128
use GraphQL\Validator\ValidationContext;
29+
use Symfony\Component\HttpFoundation\RequestStack;
3230

3331
// TODO: Refactor this and clean it up.
3432
class QueryProcessor {
@@ -54,6 +52,13 @@ class QueryProcessor {
5452
*/
5553
protected $contextsManager;
5654

55+
/**
56+
* The request stack.
57+
*
58+
* @var \Symfony\Component\HttpFoundation\RequestStack
59+
*/
60+
protected $requestStack;
61+
5762
/**
5863
* Processor constructor.
5964
*
@@ -63,15 +68,19 @@ class QueryProcessor {
6368
* The schema plugin manager.
6469
* @param \Drupal\Core\Cache\CacheBackendInterface $cacheBackend
6570
* The cache backend for caching query results.
71+
* @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
72+
* The request stack.
6673
*/
6774
public function __construct(
6875
CacheContextsManager $contextsManager,
6976
SchemaPluginManager $pluginManager,
70-
CacheBackendInterface $cacheBackend
77+
CacheBackendInterface $cacheBackend,
78+
RequestStack $requestStack
7179
) {
7280
$this->contextsManager = $contextsManager;
7381
$this->pluginManager = $pluginManager;
7482
$this->cacheBackend = $cacheBackend;
83+
$this->requestStack = $requestStack;
7584
}
7685

7786
/**
@@ -223,24 +232,27 @@ protected function executeOperation(PromiseAdapter $adapter, ServerConfig $confi
223232
* @return \GraphQL\Executor\Promise\Promise|mixed
224233
*/
225234
protected function executeCacheableOperation(PromiseAdapter $adapter, ServerConfig $config, OperationParams $params, DocumentNode $document) {
226-
$contextCacheId = 'ccid:' . $this->cacheIdentifier($params, $document, new CacheableMetadata());
227-
228-
if (!$config->getDebug() && ($contextCache = $this->cacheBackend->get($contextCacheId)) && $contexts = $contextCache->data) {
229-
$cacheId = 'cid:' . $this->cacheIdentifier($params, $document, (new CacheableMetadata())->addCacheContexts($contexts));
230-
if (($cache = $this->cacheBackend->get($cacheId)) && $result = $cache->data) {
231-
return $adapter->createFulfilled($result);
235+
$contextCacheId = 'ccid:' . $this->cacheIdentifier($params, $document);
236+
if (!$config->getDebug() && $contextCache = $this->cacheBackend->get($contextCacheId)) {
237+
$contexts = $contextCache->data ?: [];
238+
$cid = 'cid:' . $this->cacheIdentifier($params, $document, $contexts);
239+
if ($cache = $this->cacheBackend->get($cid)) {
240+
return $adapter->createFulfilled($cache->data);
232241
}
233242
}
234243

235244
$result = $this->doExecuteOperation($adapter, $config, $params, $document);
236-
237245
return $result->then(function (QueryResult $result) use ($contextCacheId, $params, $document) {
238246
// Write this query into the cache if it is cacheable.
239247
if ($result->getCacheMaxAge() !== 0) {
240-
$cacheId = 'cid:' . $this->cacheIdentifier($params, $document, (new CacheableMetadata())->addCacheContexts($result->getCacheContexts()));
241-
$this->cacheBackend->set($contextCacheId, $result->getCacheContexts(), $result->getCacheMaxAge(), $result->getCacheTags());
242-
$this->cacheBackend->set($cacheId, $result, $result->getCacheMaxAge(), $result->getCacheTags());
248+
$contexts = $result->getCacheContexts();
249+
$expire = $this->maxAgeToExpire($result->getCacheMaxAge());
250+
$tags = $result->getCacheTags();
251+
$cid = 'cid:' . $this->cacheIdentifier($params, $document, $contexts);
252+
$this->cacheBackend->set($contextCacheId, $contexts, $expire, $tags);
253+
$this->cacheBackend->set($cid, $result, $expire, $tags);
243254
}
255+
244256
return $result;
245257
});
246258
}
@@ -290,7 +302,6 @@ protected function doExecuteOperation(PromiseAdapter $adapter, ServerConfig $con
290302
);
291303

292304
return $promise->then(function (ExecutionResult $result) use ($context) {
293-
294305
$metadata = (new CacheableMetadata())
295306
->addCacheContexts($this->filterCacheContexts($context->getCacheContexts()))
296307
->addCacheTags($context->getCacheTags())
@@ -451,13 +462,13 @@ protected function sanitizeRecursive(array $item) {
451462
/**
452463
* @param \GraphQL\Server\OperationParams $params
453464
* @param \GraphQL\Language\AST\DocumentNode $document
454-
* @param \Drupal\Core\Cache\CacheableMetadata $metadata
465+
* @param array $contexts
455466
*
456467
* @return string
457468
*/
458-
protected function cacheIdentifier(OperationParams $params, DocumentNode $document, CacheableMetadata $metadata) {
469+
protected function cacheIdentifier(OperationParams $params, DocumentNode $document, array $contexts = []) {
459470
// Ignore language contexts since they are handled by graphql internally.
460-
$contexts = $this->filterCacheContexts($metadata->getCacheContexts());
471+
$contexts = $this->filterCacheContexts($contexts);
461472
$keys = $this->contextsManager->convertTokensToKeys($contexts)->getKeys();
462473

463474
// Sorting the variables will cause fewer cache vectors.
@@ -489,4 +500,19 @@ protected function filterCacheContexts(array $contexts) {
489500
return strpos($context, 'languages:') !== 0;
490501
});
491502
}
503+
504+
/**
505+
* Maps a cache max age value to an "expire" value for the Cache API.
506+
*
507+
* @param int $maxAge
508+
*
509+
* @return int
510+
* A corresponding "expire" value.
511+
*
512+
* @see \Drupal\Core\Cache\CacheBackendInterface::set()
513+
*/
514+
protected function maxAgeToExpire($maxAge) {
515+
$time = $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME');
516+
return ($maxAge === Cache::PERMANENT) ? Cache::PERMANENT : (int) $time + $maxAge;
517+
}
492518
}

0 commit comments

Comments
 (0)