Customizing Headless Proxy Output Caching

When building a site on Sitecore Headless / JSS you’ll eventually end up hosting it on a Headless Proxy Node instance. The Headles Proxy will perform server-side rendering of the page HTML for initial requests i.E. when you hit F5 (browser refresh). Subsequent requests are then usually rendered in the browser. So far so good.

Throwback: Good ol’ Sitecore MVC

Sitecore MVC has a feature called “HTML Cache”. The rendered output of components would be cached thus saving CPU time on the next request. The entire HTML Cache would be automagically cleared whenever an author published any item. Sure, there might be more sophisticated ways of clearing cache, but this did the job for most cases.

Node Output Caching

With JSS, the load of generating HTML is moved away from the Content Delivery server to the Headless Proxy (for initial requests). This takes time and CPU because Node.js needs to call layout service AND execute the application built on JSS in order to output the rendered page. Server-side rendering on the initial request will amost always be slower than the same site built on MVC – but subsequent requests will make this up to a degree because they’re rendered in the client.

What can be done to improve initial page load? Sitecore docs suggest enabling Node Output Caching as a counter-measure but there are caveats:

  • No way of clearing cache if content is changed
  • No built-in tracking via layout service
  • No user context i.E. item security
  • No personalisation

Customizing Node Output Caching

To mitigate the cache clearing issue, have a look at this custom cache middleware that works in conjunction with an API controller on the Content Delivery server:


Tracking timestamp of last publish:

public class LastPublishTimestampHandler
{
		public static DateTime LastPublishTimestamp = DateTime.Now;

		public void UpdateTimestamp(object sender, EventArgs args)
		{
			LastPublishTimestamp = DateTime.Now;
		}
}
<events>
	<event name="publish:end">
		<handler type="Foundation.Jss.Events.PublishEnd.LastPublishTimestampHandler, Foundation.Jss" method="UpdateTimestamp" />
	</event>
</events>

API Controller which is polled by Node’s Middleware

public class JssOutputCachingController : ApiController
{
	private readonly BaseSettings _settings;
	
	public JssOutputCachingController(BaseSettings settings)
	{
		this._settings = settings;
	}

	[HttpGet]
	public IHttpActionResult Status()
	{
		return Json(new {
			OutputCacheEnabled = _settings.GetBoolSetting("Jss.OutputCaching.Enabled", false),
			LastPublish = LastPublishTimestampHandler.LastPublishTimestamp,
		});
	}
}

Note: If you’re using Experience Edge, this could also be done using a webook and an azure function that stores the last publish date.

Polling Cache Middleware:

Last but not least, here’s an example of a polling cache middleware on Node. It will poll the API controller above for publish changes and clears the cache if anything has been published:

Do I need all this?

Maybe not. Maybe enabling output caching with a short cache-duration is sufficient if you’re not using personalization. Thats essentially up to your requirements. I would always suggest though to enable some sort of output caching to prevent load spikes caused by crawlers or peak traffic.

Feel free to use the code examples above as inspiration to build your own custom Cache Middleware.


Leave a Reply

Your email address will not be published. Required fields are marked *