From b148ed2368a8c113cb8d700d5cd136453543dcf5 Mon Sep 17 00:00:00 2001 From: "D. Berge" Date: Thu, 2 Nov 2023 11:59:42 +0100 Subject: [PATCH] Add refresh-project-summary periodic task. It listens for events that might indicate that the project_summary materialised view needs to be refreshed and schedules a refresh. Refreshes are throttled to a maximum of one every throttlePeriod milliseconds so that things don't get too crazy for instance when importing a lot of data. --- lib/www/server/periodic-tasks/tasks/index.js | 3 +- .../tasks/refresh-project-summary.js | 85 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 lib/www/server/periodic-tasks/tasks/refresh-project-summary.js diff --git a/lib/www/server/periodic-tasks/tasks/index.js b/lib/www/server/periodic-tasks/tasks/index.js index c5643da..09d0fce 100644 --- a/lib/www/server/periodic-tasks/tasks/index.js +++ b/lib/www/server/periodic-tasks/tasks/index.js @@ -1,4 +1,5 @@ module.exports = [ - require('./purge-notifications') + require('./purge-notifications'), + require('./refresh-project-summary') ]; diff --git a/lib/www/server/periodic-tasks/tasks/refresh-project-summary.js b/lib/www/server/periodic-tasks/tasks/refresh-project-summary.js new file mode 100644 index 0000000..2b07380 --- /dev/null +++ b/lib/www/server/periodic-tasks/tasks/refresh-project-summary.js @@ -0,0 +1,85 @@ +const db = require('../../lib/db'); +const { listen } = require('../../lib/db/notify'); +const { ALERT, ERROR, WARNING, NOTICE, INFO, DEBUG } = require('DOUGAL_ROOT/debug')(__filename); + +const timeout = 30*1000; + +async function init () { + INFO("Setting up task"); + + // Full list of channels in + // ../lib/db/channels + const channels = [ + "project", + "preplot_lines", "preplot_points", + "raw_lines", "raw_shots", + "final_lines", "final_shots" + ]; + + const throttlePeriod = 10*1000; + + const projects = {}; + + listen (channels, (data) => { + // Something important has changed, + // set the dirty flag for the relevant project + const pid = data.payload?.pid ?? data.payload?.new?.pid ?? data.payload?.old?.pid; + if (pid) { + if (!pid in projects) { + projects[pid] = { + lastRefreshed: 0 + }; + } + if (!projects[pid].needsRefresh) { + projects[pid].needsRefresh = true; + DEBUG("Setting up refresh flag for %s: %j", pid, projects[pid]); + } + } + }); + + const task = async () => { + for (pid in projects) { + const project = projects[pid]; + if (project.needsRefresh) { + const now = Date.now(); + const lastRefreshAge = now - project.lastRefreshed; + if (lastRefreshAge > throttlePeriod) { + // Do the actual refresh + try { + DEBUG("Refreshing", pid); + await db.project.summary.refresh(pid); + } catch (err) { + if (err.status == 404) { + DEBUG("Project %s not found. Removing from refresh list", pid); + delete projects[pid]; + } else { + ERROR(err); + } + } + project.needsRefresh = false; + project.lastRefreshed = now; + } + } + } + }; + + // Let us populate the project list and do a first refresh on startup + for (const project of await db.project.get()) { + projects[project.pid] = { + lastRefreshed: 0, + needsRefresh: true + } + } + task(); // No need to await + + return task; +} + +async function cleanup () { +} + +module.exports = { + init, + timeout, + cleanup +};