/**
* Caches entity normalizations after the response has been sent.
*
* @internal
* @see \Drupal\jsonapi\Normalizer\ResourceObjectNormalizer::getNormalization()
* @todo Refactor once https://www.drupal.org/node/2551419 lands.
*/
class ResourceObjectNormalizationCacher implements EventSubscriberInterface {
The issue in that @todo has landed, so it's time to stop abusing the render cache :)
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | interdiff.txt | 2.01 KB | kristiaanvandeneynde |
| #23 | drupal-3379984-23.patch | 10.28 KB | kristiaanvandeneynde |
Comments
Comment #2
kristiaanvandeneyndeSomething like this, so much cleaner.
Comment #4
kristiaanvandeneyndeThis fixes NodeTest, it was testing the caching layer directly. No clue why MenuLinkContentTest would fail all of a sudden because there is zero change being made other than swapping out the cache with the one render cache now uses internally anyway.
Comment #6
bbralaLocally this test works as intended, which confuses me. I've triggered 2 more runs, see if it was a fluke.
Comment #7
kristiaanvandeneyndeYeah as I mentioned on Slack, the jsonapi tests sometimes fail in weird ways, most recently for me in #3376846: Implement the new access policy API. I've submitted the work to convert to the new variation cache and it would be awesome if someone with more jsonapi knowledge (I have almost zero) could fix this sole test failure.
Comment #8
kristiaanvandeneyndeDo not commit this, but this makes it go green locally. So it seems the test is running into caching issues because triggering a role save makes it work. I've run into quite a few occasions where the jsonapi tests go out of sync because they run multiple requests from one process and then you have to call
$this-refreshVariables()to get the test back in sync.But, at first sight, this does not seem like such a case. It really seems like there might be a bug in the test or jsonapi here because the VariationCache now powers the render cache. So swapping out the workaround using the render cache with a direct VariationCache call shouldn't change anything.
Either way, let's see what the testbot says, but patch from #4 is still the current one we need to focus on.
Comment #9
kristiaanvandeneyndeOne thing I noticed is that RenderCache still contains this piece of code:
Which, as explained in the comment, makes sense for render arrays, but not for other services abusing the render cache by dumping just anything into a render array. This is the only thing that does not run when you swap from render cache to VariationCache, so that might be the culprit.
isMethodCacheable() returns TRUE for GET and HEAD so, before, nothing in that test would get cached aside from the penultimate GET call. Now, all POST requests above that also get cached (if jsonapi allows it, I don't know jsonapi that well). Either way, it might be that the test was written around a broken cache implementation because it sure seems as ResourceObjectNormalizationCacher would cache nothing but GET/HEAD requests in the past.
This also seems to be proven by the fact that NodeTest::assertCacheableNormalizations() checks using GET. I'm fairly sure if we change said test to use POST, PATCH or whatever that isn't GET/HEAD, that it would fail with the old code and succeed with the new.
Comment #11
kristiaanvandeneyndeHuh, locally on PHP 8.1 it goes green with the latest patch and red without. Seems like @bbrala is facing similar things.
Comment #12
kristiaanvandeneyndeThis keeps the behavior of render cache where only GET and HEAD are considered cacheable. This was not necessary for other parts of core where we swapped out the render cache use with VariationCache (such as DynamicPageCacheSubscriber), but it might make sense here because jsonapi actively deals with HTTP methods in requests.
Either way, the fact that, without this, the test would still go green for POST but not PATCH when we cache all HTTP methods worries me. It seems like using the render cache for this long obscured a potential bug in jsonapi, so I left a @todo in this patch to follow up and investigate on why the tests failed for PATCH when we cache all HTTP methods.
Having said all of that, I expect this patch to go green because now it's fully idempotent compared to the old behavior.
Comment #13
bbralaAfter a few hours of investigation i made this child issue: #3381898: Cache POST/PATCH in ResourceObjectNormalizationCacher breaks MenuLinkContentTest . This patch above works as intented, unfortunately only menulinkcontenttest is broken if we add caching for post and patch. Rest of the entities work fine.
So for now no extra caching.
Perhaps the todo in that piece of code should also mention #3381898: Cache POST/PATCH in ResourceObjectNormalizationCacher breaks MenuLinkContentTest ? Not married to that, but will probably help later. Other than that i'd RTBC.
Comment #14
kristiaanvandeneyndeUpdate the @todo in both places.
Comment #15
bbralaas per slack and #13
Comment #16
quietone commentedI'm triaging RTBC issues. I read the IS, the comments and the comments in the MR. I didn't find any unanswered questions or other work to do.
It is nice to see a bug uncovered and a follow up made for that.
Also, three is a meta for fixing all @todos for a closed issues. The IS over there needs to be updated with this so everyone know this one has an issue in progress. Actually, I can do that now. I have updated the Meta and made this a child of that one.
Leaving at RTBC.
Comment #17
kristiaanvandeneyndeThanks for the reviews!
Comment #18
catchIt's not clear to me why we'd ever want to cache PUT and PATCH responses which are likely to invalidate the cache anyway. Also in comments we don't usually refer to the past status of the code base, I understand why it's been done here, but if you don't have the history you'd really wonder why we're explaining the code currently does the same thing as it used to do but in the future might not.
Could be something like '@todo investigate whether to cache POST and PATCH requests'?
Comment #19
kristiaanvandeneyndeWe did uncover that POST/PATCH works for all but one test. That's why the @todo points to #3381898: Cache POST/PATCH in ResourceObjectNormalizationCacher breaks MenuLinkContentTest where this is specifically being addressed. Having said that and not being too well versed in the ways of jsonapi, if POST/PATCH return the object that was created or updated, then it makes no sense to cache those responses as they will always be invalidated on the next POST/PATCH call.
How about:
Splitting it up into two @todos means we could either fix the failing test and still keep the first @todo under discussion or fix them both in one go. Keeping the reference to the other DO issue also gives some background on why this is being discussed in the first place.
Comment #20
bbralaJSON:API returns a resource after patch. And it wouldn't neccesarily invalidate cache, what if nothing changed in the patch request? Then jsonapi could return a cached response for that resource. In naive implementations of patching a lot of resources this could be quite helpfull in speeding up those requests.
Post is a little harder to imagine no change, so thats pretty valid. Although I wonder if the currect setup also disable cache on perhaps permission denied requests that get responded. That is something that could be validated.
So thinking through this a todo in the line of '@todo investigate whether to cache POST and PATCH requests' is a good option to give a better context.
posted same second as krisstiaan
Comment #21
bbralaThink that change is fine @kristiaanvandeneynde although `@todo investigate whether to cache POST and PATCH requests` is a little more explicit than your todo.
I'd also say keep the reference to the issue. But perhaps in that issue we'd need to add the question if it even makes sense.
Comment #22
kristiaanvandeneyndeRe #21 Okay, updated as such. Setting back to RTBC as this is merely a comment change.
Comment #23
kristiaanvandeneyndeActually, this is what you get when trying to be quick and use patch workflow. I forgot to update it in the other place. Leaving at needs review because I am too trigger happy it seems. Sorry about that, trying to squeeze this in between project work.
Comment #24
bbralaDon't mean to be rude, but could you add an interdiff? That helps review a lot:
https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupa...
Comment #25
kristiaanvandeneyndeSure thing, should have used MR from the start to be honest :D
Comment #26
bbralaHopefully this is clear enough now. :)
Comment #28
catchMy last question was should/could this do 'best effort' bc where we keep the method (as a no-op) and trigger a deprecation.
Presumably if someone had wired this class up or subclassed it or something, then all the other changes would break that anyway. And also it's an event subscriber which is equivalent to a hook implementation, no-one should rely on it.
so... answering my own question: no, let's not try to do that.
Committed fde6ee3 and pushed to 11.x. Thanks!
Comment #29
wim leersNice!