CUTR-at-USF / usf-mobullity

USF Maps responsive web application
http://maps.usf.edu/
8 stars 7 forks source link

Cache-Control and Deployment Conflict #390

Open jmfield2 opened 7 years ago

jmfield2 commented 7 years ago

Summary:

Since we added a cache-control header to static assets (JS, etc) served by Grizzly, it seems like it is more problematic to redeploy mobullity without issues on the client-side where old files are used instead of newer files.

Steps to reproduce:

Load the website after it is redeployed and note that sometimes a forced refresh is required before the new assets are served.

Expected behavior:

New assets should be served in accordance with the "If-Modified-Since" headers sent.

It seems like this isn't happening because the netbalancer has no way to know (?) that the content has changed since max-age hasn't elapsed.

Other than somehow invalidating the cache with the balancer, other solutions might be:

1) Use cache-control: must-revalidate (in case it isn't the default in our case) 2) Lower the max-age from the current 604800 seconds (1 week) to something less like 1 day 3) Add ?param (like a version number) cache-busters to the URL of static assets upon deployments. 4) Disable serving cached assets @ netbalancer if possible

Observed behavior:

Static assets are served despite having been changed upstream. This is likely the result of the netbalancer not invalidating the cache since it doesn't actually know the content changed.

In my local testing redeploying the Java webapp does seem to handle the if-modified-since header correctly and responds with a 200 OK response for changed assets. (Observe that a 200 is followed by a 304 and then a 200 after redeploying)

Platform:

Java 1.8 Linux, Firefox, Chrome

jmfield2 commented 7 years ago

Note that this perhaps may not have anything to do with the netscaler since mobullity also seems to have similar issues with caching.

Also, some assets (images), and the POI system in particular seem to insist on being served from local cache despite a ctrl-f5 refresh.. We might need to do more robust handling of the cache headers here (like check the date the graph was built) and serve a 304 not modified response instead of always a 200 ok.

jmfield2 commented 7 years ago

I think this issue is caused by a bug in upstream Grizzly (https://github.com/GrizzlyNIO/grizzly-mirror/blob/2.3.x/modules/http-server/src/main/java/org/glassfish/grizzly/http/server/filecache/FileCache.java#L822)

Basically, the logic it uses to test whether to honor the IfModifiedSince header I think is wrong - causing it to never issue a correct 200 OK if the header value is < than the file mtime, but will issue an incorrect 200 OK if the header value is > the file mtime and an incorrect 304 not modified if the header value is < the file mtime.

I figured this out by directly testing different header values via the following curl statements and inspecting the output. The observed behavior explains what we see with this issue, and is contrary to the HTTP specification AFAICT and also the observed behavior of the Varnish cache, Apache (trimet), and IIS (usf.edu).

Flipping the <= with a >= fixes the issue.

Also note that in the same file, the logic for whether the file is "IfUnmodiifedSince" is the same.

curl 'https://localhost:8081/js/otp/core/Map.js?v=1' -H 'If-Modified-Since: Mon, 19 Dec 2016 04:13:07 GMT' --compressed --insecure

barbeau commented 7 years ago

This is the issue tied to the commit that changed the IfModifiedSince logic and seemed to introduce the bug: https://java.net/jira/browse/GRIZZLY-1222

jmfield2 commented 7 years ago

Submitted an issue and gist to: https://java.net/jira/browse/GRIZZLY-1881

jmfield2 commented 7 years ago

This should be fixed in: 2.3.x: 643a55fe1f7c30978d8cdf82a5ed273bafcc26f4 master: ccd3cc07f8811925b408b227811c4fda2e1ac340