Page MenuHomePhabricator

Adding a hash to the concatenated JS file to avoid caching issues
Closed, ResolvedPublic3 Estimated Story Points

Description

Let me try to phrase the current issue:

Caching issue
Whenever we deploy a new version of index.bundle.js, an outdated version of index.bundle.js is still loaded by many clients for a period of time.
There is varnish cache (on the server) and browser cache (on the client).

Varnish cache
We now have 2 files cached in varnish:

  • index.html
  • index.bundle.js

Varnish caches these files independently, for a configured period of time (= 3600s).

Solution
To prevent out-of-sync files, we can either:

  1. rename the JS file to a hashed named. index.bundle.js becomes index.{hash}.js
  2. append a query parameter to the JS file. index.bundle.js becomes index.bundle.js?rev={hash}

So that the HTML knows exactly what revision it wants to load.

Problem with both options:

  • During deployment the assets folder needs to be synced before index.html
    • otherwise for X milliseconds, the html points to a JS file that does not exist on the server yet and varnish will cache the 404 for 5 minutes.
      • this means the page will behave like if the user had JavaScript disabled for 5 minutes.

Problem with option 1:

  • We will generate a new file for each change. So we need to remove old files after some X period of time.
    • Kinda hard to automate.
  • If we clean the folder on each build/deployment,
    • until varnish caches the new html file, varnish will keep returning the cached old JS file for a bit (even if it got removed on the server), and once it's expired varnish will return a 404 (for 5 minutes) thus giving people a page without JS.
      • @JGirault: As a user, I would hate to suddenly get a poor JS-free user experience for no apparent reason.

Problem with option 2:

  • If index.bundle.js in varnish expires before index.html, then the server/varnish will return the cached old html file AND the new version of the JS file (even though it has the right old revision appended)
    • it is only a problem if the new JS file only works for the new html file and breaks with the old one.
    • it is only a problem when you change both the JS + the HTML file and the new JS does not provide backward compatibility.

Compromise possible:

  • We go with option 2 (appending ?rev={hash} ), and when we know the JS has no backward compatibility with the old html (change in the DOM structure), we rename the new file to newindex.bundle.js and maintain the old index.bundle.js on the server for some time.
    • The old version needs to stay online more than varnish expiration time.
    • No automation possible, deciding to rename the file and doing it must be manual.
      • Our build script can have a config object {previous_production_file_name: 'index.bundle.js', new_production_file_name: 'newindex.bundle.js'} to automatically preserve the old file, generate the new file, and clean the folder of any other file.
        • (if we don't want to be this creative, we can also use a number {previous_production_file_number: 1, new_production_file_number: 2} will do bundle-1.js and bundle-2.js)

/cc @MaxSem & @EBernhardson to review and correct me if I am writing non-sense

Event Timeline

JGirault claimed this task.
JGirault raised the priority of this task from to Needs Triage.
JGirault updated the task description. (Show Details)

Hi @MaxSem - can't we flush the varnish cache and force it to update to the new file when we do the deployment? So that there isn't any weird latency in getting the new code?

debt triaged this task as High priority.Feb 1 2016, 8:10 PM
debt moved this task from To Discuss to What's Next on the Discovery-Portal-Sprint board.