5.1K
Keep slow Drupal HTML responses cached and fresh.
Islandora/Drupal's internal page cache system is wiped whenever drush cr is called. Since deployments require a drush cr this results in degraded performance of the site after deployments.
Traditionally, the only way to recover from the degraded state would be a site visitor accessing a given page (which would fill the cache for that page for other site visitors). Waiting for organic hits to fill the cache would likely result in many poor experiences for the first visitor for each page needing filled. Waiting for organic cache fills also means there's a fairly large window for a potential cache stampede if the site were to see a sudden surge of organic traffic after a deployment.
A custom crawler could also be leveraged to help fill the cache after deployment. This would help mitigate site visitors from experiencing slow page loads, but to avoid overloading the system that crawling process can take several hours to traverse a large site. That means a larger time window for site visitors to have poor experiences.
Keep the three slowest HTML responses from Drupal cached on disk to persist beyond cache flushes. Only have this service invalidate the responses based on events emitted by Islandora/Drupal this service listens for.
/node/\d+/book-manifests)/node/\d+)/browse)When code deployments happen, send an event to this service to invalidate/cache the entire site
sequenceDiagram
actor Developer
Developer->>GitLab: git push
GitLab->>Islandora: deploy
Islandora->>activemq: emit message to cache-warmer microservice<br>queue:islandora-cache-warmer
scyllaridae->>activemq: read message
note over scyllaridae,Islandora: get all pages from sitemap
scyllaridae->>Islandora: cURL /sitemap.xml
loop for URL in sitemap.xml
scyllaridae->>Islandora: curl $URL
end
note over scyllaridae,Islandora: all nodes cache are now warm<br>now get all Islandora nodes with children<br>to cache our IIIF manifests
scyllaridae->>Islandora: cURL /paged-content-nids
Islandora->>scyllaridae: PAGED_CONTENT_NIDS
loop for NID in PAGED_CONTENT_NIDS
scyllaridae->>Islandora: curl /node/$NID/book-manifest
end
note over scyllaridae,Islandora: all IIIF manifests are now warm
When a node is CUD, an event is emitted to fill the cache for that node, its parent, and the IIIF manifest.
sequenceDiagram
actor Content editor
Content editor->>Islandora: save node
Islandora->>activemq: emit message to cache-warmer microservice<br>queue:islandora-cache-warmer
scyllaridae->>activemq: read message
note over scyllaridae,Islandora: fill node cache
scyllaridae->>Islandora: curl /node/$NID
Islandora-->>scyllaridae: HTTP/1.1 200
note over scyllaridae,Islandora: fill IIIF manifest cache
scyllaridae->>Islandora: curl /node/$PARENT_NID/book-manifest
Islandora-->>scyllaridae: HTTP/1.1 200
If we hold the cached responses on disk instead of in Drupal's database cache we can invalidate the cache on a per node basis after deployment. This means after a deployment until the cache is invalidated // warmed site visitors will still enjoy a speedy site. Old cached entries will be served until the deployment script can invalidate them and fill the cache with their new version.
We can also emit events on node/media CUD events to have the anonymous view kept warm after entity updates using this same mechanism.
Putting Drupal behind a CDN or Varnish is a common pattern for site speed improvements. In general, both a CDN and Varnish were not chosen to avoid adding additional complexity to the ISLE stack. The ISLE stack already includes an event driven microservice architecture which we can leverage to keep our caches fresh. If that microservice architecture was not in place, a CDN or Varnish would have been given more serious consideration.
A CDN was disqualified since it would require not only additional integration complexity, but also would add additional cost to your site, which we are trying to keep at a minimum. It also has similar shortcomings related to relying on HTTP headers as detailed further in the below Varnish section.
Varnish was not chosen to avoid the complexity of adding an additional service to our stack. Adding Varnish would mean needing to configure VCL for the Varnish server and also configuring cache invalidations with something like the Drupal purge module. Instead, it was decided to have the cache handled internally with a custom event subscriber (this is analagous to what varnish would be doing) and hook_entity_CUD implementations to keep the cache fresh (instead of the purge module).
This leads to another key decision point why Varnish was not chosen over this custom implementation: Varnish can only really handle cache variants based on HTTP headers returned by Drupal's response. Since we're implementing the cache within Drupal we have much more flexibility about cache variants and deciding when something can be cached, how it is cached, and when that cache needs invalidated or when it's safe to serve to site visitors. Implementing something like this in Varnish I'm sure could be done, but implementing and debugging would require context switching between php and VCL and massaging HTTP headers to be emitted and received properly by the two languages/programs. This leads back to the original point: this solution reduces the complexity of our tech stack by having the caching logic in Drupal.
More to the point: since the caching logic is controlled within Drupal we can cache responses per-user. Effectively making the implementation a private and public cache store.
Positive:
Negative:
This will be implemented by:
hook_node/media_insert/update/delete() implementations to wipe the cached responses from the filesystemUpdate your docker-compose.yml with
cache-warmer-prod: &cache-warmer-prod
<<: [*prod, *common]
image: ${DOCKER_REPOSITORY}/scyllaridae-cache-warmer:main
environment:
DRUPAL_URL: "https://${DOMAIN}"
# when warming the cache, how many nodes to process at once
NODE_PARALLEL_EXECUTIONS: 5
# when warming the cache, how many IIIF manifests to process at once
IIIF_PARALLEL_EXECUTIONS: 3
depends_on:
activemq-prod:
condition: service_started
You'd also need an accompanying Drupal module to handle disk caching/invalidation on the Drupal side, which can eventually be broken out of lehigh-university-libraries/lehigh_islandora
Content type
Image
Digest
sha256:fbf0c9788…
Size
95.2 MB
Last updated
about 1 year ago
docker pull lehighlts/scyllaridae-cache-warmer:mainPulls:
9
Last week