Conversation
Todo: - [x] Add cache for all load operations used by UI and other clients -- [x] Add slots to trigger tag clearing on more operations (content type, sections..) - [ ] Adjust existing CachedValue use to add more relevant tags and not just locationId
bdunogier
left a comment
There was a problem hiding this comment.
Partial review, but some elements can be discussed already.
| - `LOCATION_CACHE_DIR` and `LOCATION_STALE_CACHE_DIR` and related functionality is gone as tags are used instead | ||
| - See `doc/specifications/cache/multi_tagging.md` for further details. | ||
|
|
||
| * Smart cache clearing is currently disabled, and might come back in form where it generate tags to clear, |
There was a problem hiding this comment.
Could we list what will be affected by that ? Mostly thinking about clearing that used to be performed, and wouldn't anymore with these changes.
| opposed to that it is done. | ||
|
|
||
| But to avoid stale cache issues caused by cache being refreshed before search index is or similar, it is now important | ||
| that HTTP Cache ttl *(default_ttl)* is not set to high, especially for REST endpoints used by UI. |
|
|
||
| $this->cacheManager->invalidate(array('X-Location-Id' => '^(' . implode('|', $locationIds) . ')$')); | ||
| // @todo: Need to take advantage of xkey if enabled to avoid BAN unless VCL handles this for us. | ||
| $this->cacheManager->invalidate(array('xkey' => '^(' . implode('|', $tags) . ')$')); |
There was a problem hiding this comment.
Short array syntax while at it ?
| public function purgeAll() | ||
| { | ||
| $this->cacheManager->invalidate(array('X-Location-Id' => '.*')); | ||
| $this->cacheManager->invalidate(array('xkey' => '.*')); |
|
|
||
| - `content-type-<content-type-id>` | ||
|
|
||
| *Tagging*: Used for tagging content responses with type id. |
There was a problem hiding this comment.
What about other response types, such as content type ? We don't currently cache responses from the content type controller, but if we have content-type tags, we can very do it.
There was a problem hiding this comment.
Note that the PR's description gives ContentTypes as a first example of what could be cached thanks to this.
In that case, the HttpCache slots on ContentType service are missing for this.
| *Clearing*: When a operation is specifically affecting parent location(s), on tree operations `path` is more relevant. | ||
|
|
||
| - `path-<path-location-id>` | ||
|
|
| *Clearing*: When a operation is specifically affecting just given content. | ||
|
|
||
|
|
||
| - `content-type-<content-type-id>` |
There was a problem hiding this comment.
What about content-type-group-<content-type-group-id> ? It would be useful for list of content types by group, to expire those when a new content-type is added to the group.
| and the signals will need to be expanded to contain the relevant info depending on operation they correspond to. | ||
|
|
||
|
|
||
| ### Predefined System Tags |
There was a problem hiding this comment.
Do we want to add a tag for Roles as well ?
fb76ba6 to
1f14100
Compare
Conflicts: eZ/Publish/Core/MVC/Symfony/Cache/Http/LocationAwareStore.php eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/PurgeForContentHttpCacheSlot.php eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/LocationAwareStoreTest.php
af04a9f to
4ec7994
Compare
| /** | ||
| * Returns the Relations for the current entity being viewed. | ||
| * | ||
| * @return \eZ\Publish\API\Repository\Values\Content\Relation[] |
There was a problem hiding this comment.
@bdunogier Note: I assumed you would prefer full object, but for tag needs I just need to keep id's around, and if we did that we could optimize the loading of relational data to only be one spi calls instead of 1+n (where n is number of relations). The design of this does not make a differance when cached, but it does make a differance in dev (either on cold cache or with cache disabled).
There was a problem hiding this comment.
Input from @bdunogier, instead of doing this no matter if relation is rendered or not we should use manual tagging in this case. there is a twig function by fos_http_cache for this.
For some reason host is not being applied, so this might be a workaround for something else going on here. The exception given is: https://github.com/FriendsOfSymfony/FOSHttpCache/blob/1.4/src/ProxyClient/Varnish.php#L141-L145
bdunogier
left a comment
There was a problem hiding this comment.
Managed to dive a bit deeper into it.
Overall, I think it's good. I still have doubts in regards to tagging responses. As discussed face-to-face, we might be able to make that MUCH easier for developers by tracking API calls, and tagging the response based on API values that have been loaded.
But maybe it's too much for the time being ?
Do you want me to take care of the some of the todos, or did you intend to do it yourself ?
|
|
||
| #### Other eZ Repository domains | ||
|
|
||
| Tags for other domains in the Repository also have tags, e.g.: |
There was a problem hiding this comment.
There can be only one "tag" in this sentence, methinks :)
| @@ -1,255 +0,0 @@ | |||
| <?php | |||
There was a problem hiding this comment.
BC: could we leave the file where it is, and mark it as deprecated ? It doesn't cost anything as long as we handle removals for 7.0.
There was a problem hiding this comment.
but if someone use it they won't get a clear error saying they need to adapt, they'll continue using that and it won't work as headers are different.
There was a problem hiding this comment.
Hmm, we can add deprecation warnings, can't we ?
They will for sure notice if they were using it and we remove it :)
There was a problem hiding this comment.
Hmm, we can add deprecation warnings, can't we ?
we can, so you prefer that then, and that deprecation warning says class most likely won't work anymore.
There was a problem hiding this comment.
Well, the warning should say which class replaces it. The class works, it's just not used anymore. If somebody has a service that uses it, it will throw the warning during container compilation.
Unless you're really against it, I prefer it that way. Thank you :)
|
|
||
| /** | ||
| * Injects a Filesystem instance | ||
| * For unit tests only. |
There was a problem hiding this comment.
I'd maybe prefer if we removed this from the class, and handled this in unit tests:
- either using reflection
- or by making
$fsprotected and adding a test class that extendsTagAwareStoreand adds this method.
Just saw that the getCachePath method below is public for the same reason, but it could be solved if it was a dep, as suggested.
| $this->fs = new Filesystem(); | ||
| } | ||
|
|
||
| return $this->fs; |
There was a problem hiding this comment.
As in why do we need getFilesystem()? I'll have to check, as many of your other questions it's inherited from the previous class.
There was a problem hiding this comment.
The question was actually why we needed the if (!isset())... new part.
The fact that it comes from the parent class is a good reason.
| $digest = $response->headers->get('X-Content-Digest'); | ||
| $tags = $response->headers->get('xkey', null, false); | ||
|
|
||
| if ($response->headers->has('X-Location-Id')) { |
There was a problem hiding this comment.
Should we also remove the header ? Or is this handled somewhere else ?
There was a problem hiding this comment.
This can be logged as separate enhancement, it was not covered before, and parent Store class does not seem to strip anything either.
| public function purgeAllContent() | ||
| { | ||
| $cacheTagsCacheDir = $this->getTagPath(); | ||
| $this->getFilesystem()->remove($cacheTagsCacheDir); |
There was a problem hiding this comment.
This method is supposed to return bool. Since remove doesn't return anything, maybe we should catch exceptions it sends, and return true/false depending if something was caught ?
There was a problem hiding this comment.
I'll need to check against old class, might be we can adjust doc here.
| } | ||
| } | ||
| $fs->remove($files); | ||
| // we let folder stay in case another process have just written new cache tags |
| // Flip the tag so we put id first so it gets sliced into folders. | ||
| // (otherwise we would easily reach inode limits on file system) | ||
| $tag = strrev($tag); | ||
| $path .= DIRECTORY_SEPARATOR . substr($tag, 0, 2) . DIRECTORY_SEPARATOR . substr($tag, 2, 2) . DIRECTORY_SEPARATOR . substr($tag, 4); |
There was a problem hiding this comment.
Could be:
$path .= implode(
DIRECTORY_SEPARATOR,
array_slice(str_split(strrev($tag), 2), 0, 4)
);
Not sure it's better, but it's different. Maybe easier to make configurable (folder length, number of folders).
Did you consider making this an external service ? It's an important responsibility, and it could be worth testing individually.
There was a problem hiding this comment.
I kept it like this as this is how it is done upstream in Symfony for getPath(), I also find this more readable then the example you propose even if it indeed avoids the long line.
| * @copyright Copyright (C) eZ Systems AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| * | ||
| * @version //autogentag// |
| $this->fs = new Filesystem(); | ||
| } | ||
|
|
||
| return $this->fs; |
There was a problem hiding this comment.
As in why do we need getFilesystem()? I'll have to check, as many of your other questions it's inherited from the previous class.
| public function purgeAllContent() | ||
| { | ||
| $cacheTagsCacheDir = $this->getTagPath(); | ||
| $this->getFilesystem()->remove($cacheTagsCacheDir); |
There was a problem hiding this comment.
I'll need to check against old class, might be we can adjust doc here.
| * @copyright Copyright (C) eZ Systems AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| * | ||
| * @version //autogentag// |
| * @copyright Copyright (C) eZ Systems AS. All rights reserved. | ||
| * @license For full copyright and license information view LICENSE file distributed with this source code. | ||
| * | ||
| * @version //autogentag// |
042f22e to
7ceebce
Compare
7ceebce to
136a7c1
Compare
| Examples: | ||
| - (123|456|789) => Purge locations #123, #456, #789. | ||
| - .* => Purge all locations. | ||
| - If "http" is used, only one Http PURGE request will be sent, with xkey header containing tags to purge seperated by space. |
There was a problem hiding this comment.
fix, several request are done per key, as per what xkey supports.
@bdunogier Missed that comment in the reviews, I can take care about it today, but let's sync on it so we find a good fit for doc. BTW any tought on #1772 (comment) |
3bcc152 to
5c84914
Compare
|
Replaced by http://github.com/ezsystems/ezplatform-http-cache. Please do not delete the branch yet. |
As we have own layers for HttpCache it is possible to solve this without waiting for others.
TL;DR; Multi tagging for for all solving many edge cases, very simple multi tagging support added for Symfony HttpCache Proxy in our own cache store layer, meant to be replaced by using Symfony Cache component once we move to Symfony 3.x, and change to xkey header to align with change on Varnish side to use xkey vmod for better (more stable) performance.
Solves:
Performance:
Issues:
BC
This change on purpose rather intrusive to HTTPCache layer, not all strictly needed to solve the issues, but overdue as it was somewhat jungle in there and cleanup highly needed as it has received changes over the years.
GatewayCachePurgerand implementations in favor of just the PurgeClientInterface layer.Testing
See meta PR.
Todo
FOSPurgeClientonce VCL changes are in place to alignFuture