Assessing the Impact of OKAPI's HTTP Cache on Acquisitions

Overview

This investigation was in response to a request to assess the impact of the HTTP Cache feature introduced as part of  OKAPI-770 - Getting issue details... STATUS  with regard to acquisitions.

Findings

I've looked at the OKAPI HTTP Cache feature and based on my understanding of the code can see two types of changes we might have to make in order to ensure consistent and correct operation of the acquisitions apps when this feature is enabled in OKAPI:

  1. Potentially add a response header "Cache-control: no-store" to GET responses w/ status code 200. There are roughly 157 places where this might apply - spanning 9 backend modules
  2. Potentially add a request header "Cache-control: no-store" to GET requests out to other modules. There are roughly 217 places where this might apply - spanning 15 frontend and backend repositories


We could either evaluate each of the ~375 places in the code and determine if we want to use the cache, or simply "opt-out" by blindly adding the headers in all those places w/o giving each case thought. The latter is less work and probably safer as it effectively means the cache shouldn't be used for any interactions to/from acquisitions code. That said, care must be taken going forward when writing new code that we either add the necessary headers or think through the implications of not (and using the cache for those particular calls).

If we take the easier "opt-out" approach, and create a single story for each of the modules involved we're looking at 24 user stories. If you combine the request (1.) and response (2.) work into a single story for modules which require both, that comes down to 19 user stories. In this case some of those stories are quite small, but others are quite large (mod-orders would have over 55 changes)

Here's the estimated number of code changes by repository:


## Adding "cache-control: no-store" response header:
total 133 (157 including work in progress and planned for next sprint)
-----------------
19 mod-finance
22 mod-finance-storage
17 mod-orders (+ 4 moving settings from configuration -> orders; planned for next sprint)
25 mod-orders-storage (+ 4 moving settings from configuration -> orders; planned for next sprint)
17 mod-organizations-storage
6 mod-oai-pmh
1 mod-gobi
12 mod-invoice (+ 8 batch vouchers; WIP)
14 mod-invoice-storage (+ 8 batch vouchers; WIP)

## Adding "cache-control: no-store" request header:
total 217
-----------------
18 mod-finance
0 mod-finance-storage
35 mod-orders
0 mod-orders-storage
0 mod-organizations-storage
3 mod-oai-pmh
9 mod-gobi
19 mod-invoice
0 mod-invoice-storage
34 ui-orders
44 ui-finance
10 ui-organizations
12 ui-receiving
19 ui-invoice
10 stripes-acq-components
0 ui-plugin-create-item
1 ui-plugin-find-contact
1 ui-plugin-find-instance
1 ui-plugin-find-interface
1 ui-plugin-find-organization
0 ui-plugin-find-po-line


I will say that there are likely some cases where it might make sense to use a cache - things like when looking up controlled vocabulary values which aren't likely to change frequently, if ever. However, there's bound to be times when something is cached and a user is wondering why they're not seeing something that they just changed - this leads to frustration and distrust of the system. The devil is in the details here. We need to be very careful about what we cache, how long we cache it, what the cache key is, and how we might invalidate cache entries if needed. 

There might be shortcuts that can be taken if going with the opt-out approach - within a given module we might have or be able to introduce code in one or a few places that ALWAYS adds the request header for any GET requests that module makes instead of having to add the header in N different places. This might help reduce the scope of the changes within that module, but still doesn't reduce the number of stories required.

Another thing to consider... if we're using shared components (e.g. stripes-smart-components), it might be difficult, if not impossible to add the cache-control header without reworking the code, or forking our own acquisitions version. Some of this is speculation - The UI guys would know better