JILS-41 introduced support for two new response headers
- E-Tag
- Last-Modified
And for two new request headers
- If-None-Match
- If-Modified-Since
Unfortunately on Project Index pages (also Component and Version indexes), whilst the E-Tag will update if Project properties (description, name, url etc) change, the Last-Modified date doesn't.
This is an issue, because some downstream caches (NGinx being one) only use If-Modified-Since when revalidating. So although the page content has changed, the page will revalidate.
There isn't actually a good way to get around this, as JIRA doesn't keep a log of when project/version/component properties were changed. So there isn't a date in the database we can extract to identify the most recent change (unless an issue has changed, then we can use that).
Activity
2016-04-22 13:44:35
My testbox (nginx/1.8.0) definitely isn't using it, and the NGinx caching guide (https://www.nginx.com/blog/nginx-caching-guide/) says If-Modified-Since will be used.
So it's possible If-None-Match support is more recent. Alternatively - Etags aren't currently enabled on that proxy, so perhaps they need to be turned on for it to consider etags when going upstream?
2016-04-22 14:31:00
Simply enabling etags isn't sufficient, as by default NGinx is using HTTP/1.0 to go upstream
E-tags don't exist in 1.0, so need to tell NGinx to use 1.1 when going to the origin
But even then they don't seem to be used. I'm probabyl missing a config option somewhere, will have a look at the code-base to try and see what (and when it was introduced)
2016-04-22 14:39:50
Looking at the commits against that issue (primarily https://trac.nginx.org/nginx/changeset/c95d7882dfc9ff90ee161328747114b6b54667a5/nginx ) it looks like the only config variable taken into account is proxy_cache_revalidate, which is already set.
The check's pretty simple:
2016-04-22 14:40:55
2016-04-22 14:45:26
Webhook User-Agent
View Commit
2016-04-22 14:53:57
2016-04-22 15:16:44
Just to rule out the obvious I switched the ordering of the headers, but no dice. Not that ordering should matter anyway
Updating to Nginx 1.8.1 hasn't helped either.
Doesn't seem to be anything wrong with the header, Chrome is happy to use If-None-Match when revalidating a cached copy of the page. So there's either something wrong with my NGinx config, or NGinx itself.
2016-04-22 15:32:58
After running a few tests, it seems to relate to the length of the ETag. I swapped the SHA1 for a MD5 and NGinx now presents an If-None-Match header when attempting to revalidate. Shouldn't matter as ETags are of type Entity-Tag, which according to the spec can be any length (though I had forgotten to quote them).
As the page type, and issue ID are in the clear, only need to worry about collisions within a page, so I think it should be safe to swap everything over to MD5. Will work through and do that now (and insert the errant quotes)
2016-04-22 15:59:01
and that still wasn't sufficiently short for NGinx to present an If-None-Match.
Shortening to
worked but would mean NGinx would stop using ETags for revalidation if an issues internal ID were higher than 999999. Whilst that's a fairly large JIRA install, it's not necessarily huge, so I've updated the etag generation to
So, it should work for up to 99,999,999 issues. If someone's got more than that number of issues, it's going to fall back to IMS, but there's not much can be done about that other than looking at how to adjust NGinx to remove the limitation (seems to be 40 bytes/320 bits)
I've made a similar change to all the other etags (will commit in a moment) to get those working as well, and revalidation does now seem to be using If-None-Match
Obviously it's still worth trying to think of a way to identify a Last-Modified date for Project/Version/Component pages, but NGinx will now correctly use If-None-Match, so that reduces the impact a little.
2016-04-22 16:01:27
Webhook User-Agent
View Commit
2016-04-22 16:06:46
2016-04-22 16:22:08
Although it'll accept and serve longer ETags returned from the origin, for revalidation purposes, NGinx appears to limit the length of ETags to 40 bytes. Any longer and it won't include an If-None-Match header when sending a conditional request upstream (instead falling back on If-Modified-Since).
In order for NGinx to use If-None-Match, upstream connections need to be HTTP/1.1 (because etags didn't exist in 1.0), so the following must be set (whether globally - in the http block, on a per host basis - in the server block, or within the location being proxied - in the location block)
There's no need to explicitly enable ETags with the etag directive (though you might want to enable it for other reasons).
2016-04-24 18:26:33
2016-04-29 15:17:57
2016-04-29 15:18:03
2018-01-05 08:39:50
2018-01-05 08:39:50
2018-01-05 08:39:54