We can achieve caching by setting Cache-Control header’s max-age in the HTTP response headers. In NodeJS/Express stack, you do this done by passing options map to express.static() middle-ware. Here is an example:
1 2 3 4 5 6 7
However, the challenge is to discard or bust this client cache for new code deployments. As HTTP is a stateless protocol, there is no way server can tell clients to ignore old caches and request again. If you do set max-age:0 then we shall not arrive in this situation at all. However, we want to achieve caching and refresh this cache with new code deployments. As HTTP is a stateless protocol, one simple solution is to generate a new URL for the resource. What if we append app version as query string or as folder path? i.e.
Browsers will treat this as new URL and fetch again. NPM has a plugin
validator, that exactly does this. The problem with npm:validator is – it requires to increment app version number for each new deployment or your sprint. If you forget to increment version no., you leave your clients buzzing with missing CSS classes. We can achieve this without introducing a new dependency. Let me simplify this and achieve the same using timestamps. Remember, less code keeps footprint limited! Solution In the following code we are trying to achieve a good caching period (30 days). Also this caching should not be applicable for your local development. We will be using app’s start time as a substitute of version. (We have been using AWS-EBS for production deployments and each new deployment re-starts the app, giving new time-stamp with each deployment.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
What if you have distributed deployment?
If you planning to deploy your app on AWS Elastic Beanstalk having auto scale (more than one app server), than above shall not work efficiently as each client browser may hit to new app server seeing a different time-stamp! Let’s solve this by clustering all app starts in a 5 min span.
- Serve files with an MD5 hash suffix. Try: Connect-Assets
- Using GIT log as deployVersion. Integrate GIT api in project and read last commit ID
- Incrementing app version number in each sprint :down: