Files
dougal-software/lib/www/server/api/middleware/event/cache.js
D. Berge b76f1f166b Refactor events middleware.
The reason for refactoring was to accommodate
Multiseis / client sequence exports, which will be
served by this endpoint via a specific Content-Type.

In the process, the cache has been fixed and redesigned.

Related to #12.
2020-09-26 17:41:47 +02:00

84 lines
2.1 KiB
JavaScript

const { listen } = require('../../../ws/db');
// Event responses take a long time as we are querying a view
// which is the union of other views and non-optimised tables,
// so to speed things up a bit for the user we cache the
// results here.
// We do this by indexing each result by its ETag value and
// storing the ID of the project it belongs to as well as the
// timestamp of the request. If the events for a project are
// modified in any way (addition/deletion/change) we immediately
// invalidate all cached responses for that project, else we
// delete them when they're older than maxAge (plus a delay).
// When the user sends a request with an ETag, we search for
// the ETag in our cache and return that, if present, instead
// of hitting the database.
const cache = {};
const maxAge = 90*60*1000; // 1.5 hours
setInterval(() => {
const now = Date.now();
for (const key in cache) {
const value = cache[key];
if ((now - value.tstamp) > maxAge) {
// console.log("CLEARING", key);
delete cache[key];
}
}
}, 5*60*1000); // Run every five minutes
listen(["event"], (data) => {
for (const key in cache) {
const value = cache[key];
if (value.pid == data.payload.pid) {
delete cache[key];
}
}
});
function get (req, res, next) {
try {
// console.log(cache);
const etag = req.get('if-none-match');
// console.log("ETag", etag);
if (etag && cache[etag]) {
// console.log("In cache");
if (cache[etag].headers) {
for (const header in cache[etag].headers) {
const value = cache[etag].headers[header];
if (header && value) {
res.set(header, value);
}
}
}
// 304s have no body
// https://tools.ietf.org/html/rfc7232#section-4.1
res.status(304).send();
next('route');
} else {
// console.log("Not in cache");
next();
}
} catch (err) {
next(err);
}
}
function save (req, res, next) {
const etag = res.getHeader("etag");
if (etag) {
cache[etag] = {
headers: {
"Content-Type": res.getHeader("content-type") || "application/json"
},
pid: req.params.project,
tstamp: Date.now()
}
// console.log("CACHE", cache);
}
next();
}
module.exports = { get, save };