Overview
I have a local environment with 22 code components, which isn't a lot. Drupal\canvas\Audit\ComponentAudit::hasUsages took 290ms to run. It grows in time with each code component.
I believe the problem is Drupal\canvas\Audit\ComponentAudit::getConfigEntityDependenciesUsingComponent which relies on the typed config manager to find dependencies.
Blackfire shows this calls
- Drupal\Core\Config\Entity\ConfigDependencyManager::getDependentEntities ~33 times
- Drupal\Core\Config\ConfigManager::getConfigDependencyManager ~33 times
Drupal\Core\Config\Entity\ConfigDependencyManager::createGraphConfigEntityDependencies was called once by getDependentEntities (so there must be some static caching) but it took 269ms. That was about 38% of the response time.
Proposed resolution
See if there's some way we can reliably cache the result of \Drupal\canvas\Audit\ComponentAudit::getConfigEntityDependenciesUsingComponent. The problem is that it's basically inverse of how cache tags work (the data isn't changing, but things referencing the data are.)
My "thanks I hate it" approach is to have \Drupal\canvas\Entity\Component::postSave invalidate the cache tags for any `component` it depends on. Maybe it's not that bad of an idea.
Comments
Comment #2
wim leersThis isn't a bug. We made Canvas correct, we didn't do any real work yet to make it fast. We only made sure that we made cacheable responses cacheable from the start.
Which BTW is true also for
/canvas/api/v0/config/js_component: it's cached by Dynamic Page Cache. So this slow code path already happens only when there's a cache miss. Of course, when constantly editing code components, it'll result in constant cache misses.Or are you saying it's never being cached by Dynamic Page Cache? If so, that'd indeed be a bug.
AFAICT the
Drupal\canvas\Audit\ComponentAudit::hasUsages()calls are happening when normalizing individualJavaScriptComponentconfig entities:\Drupal\canvas\Entity\JavaScriptComponent::normalizeForClientSide()calls it via this call chain:::getEntityOperations()→::access()→\Drupal\canvas\EntityHandlers\VisibleWhenDisabledCanvasConfigEntityAccessControlHandler::checkAccess()→\Drupal\canvas\Audit\ComponentAudit::hasUsages().This is missing from the issue summary.
Two possible solutions are listed. I think the first has a lot of merit, and think this is totally doable! 👍
I see a third, that might intersect with the first: bringing the equivalent of "render caching" to these API responses, aka "per-config entity normalization caching". That way, we'd end up retrieving all already-normalized config entities from cache, only needing to compute the
👆 This would speed up every internal HTTP API response.
Finally: the Component Audit functionality was introduced as MVP and has had zero performance improvements done to it, hence #3522953: [later phase] Make Component `audit` operation performant/scalable