Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Triggering a Client Cache Refresh

DZone's Guide to

Triggering a Client Cache Refresh

This walkthrough explains how to set up an automated cache-busting system to ensure clients stay up to date.

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

More and more websites are using a single-page style architecture.  This means there are a bunch of static resources (aka assets) including JavaScript, CSS, HTML templates and images all residing in the client's browser. For performance reasons, the static content is usually cached. And like all caches, eventually the data gets stale and the cache must be refreshed.  One excellent technique for achieving this in the web tier is cache busting (see: here and here). 

However, this excellent pattern there still needs to be some sort of trigger to indicate that things have gone out of date. Some options:
  1. HTML5 Sockets: In this case, a server can send a request to any client to say go and get the new stuff. 

  2. Comet style polling: The client consistently polls the server in the background asking if there is a new version available. When the server says there is, the client is triggered to start cache busting. Both of these are good approaches, but in some edge cases may not be available. 

The architecture may not allow HTML5 sockets. For example, some secure banking website just doesn't like it.

The Comet style polling might be too intensive and may just leave open edge cases where a critical update is needed but the polling thread is waiting to be fired. 

Client Refresh Notification Pattern

Recently on a project, neither of the above approaches was available, so I needed something else. The solution was based on some existing concepts already in the architecture (which are useful for other things) and some new ones that needed to be introduced:

  1. The UI always knows the current version.  This was already burnt into the UI as part of the build process.
  2. Every UI was already sending up the version it is on in a custom header. It was doing this for every request.  Note: this is very useful as it can make diagnosing problems easier. For someone seeing problems, it's nice to be able see that they're on an old version straight away.

The following new concepts were then introduced:

  1. The server would always store the latest client version it received. This is easy to do and, again, a handy thing to have anyway.
  2. The server would then always add a custom header to every response to indicate the latest client version it has received. Again, a useful thing to have for anyone doing a bit of debugging with Firebug or Chrome web tools
  3. The client would then have some simple logic so that when it saw a different version in response to the one it sent up, it knows there's a later version out there, and that's the trigger to start cache busting!   This should be done in central place—for example, an Angular filter (if you are using Angular).
  4. Then, as part of every release, just hit the server with the latest client in the smoke testing. 
  5. As soon as any other client makes a request, it will be told that there is a later client version out there, and it should start cache busting.

So, the clients effectively tell each other about the latest version, but without ever talking to each other. It's all via the server. It's like the mediator pattern. But it's still probably confusing. So let's take a look at a diagram.


With respect to diagram above: 

  • UI 1 has a later version (for example 1.5.1) of static assets than UI 2  (for example 1.5.0).
  • Server thinks the latest version of static assets is 1.5.0.
  • UI 1 then makes a request to the server and sends up version 1.5.1.
  • Server sees 1.5.1 is newer than 1.5.0 and then updates its latest client version variable to 1.5.1.
  • UI 2 makes a request to the server and sends up the version of static assets it has, which is 1.5.0.
  • Server sends response to UI 2 with a response header saying that the latest client version is 1.5.1.
  • UI 2 checks and sees that the response header client version is different from the version sent up and starts busting the cache
Before the observant amongst you start saying this will never work in a real enterprise environment, as you never have just one server (as in one JVM)—true. But in that case, you can store the latest client version in a distributed cache (e.g. Infinispan) that they can all access. 

Note: In this example I am using two web clients and one back-end server. But note the exact same pattern could be used for back-end microservices that communicate with each other. Basically, this could be used for anything where there is a range of distributed clients (they don't have to be web browsers) and caching of static resources.

Until the next time, take care of yourselves. 

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:
performance ,client ,cache

Published at DZone with permission of Alex Staveley, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}