perf: server-side caching + remove bulk status fetch from experiment page
- Add backend/src/lib/cache.js — in-process TTL Map cache with prefix-based invalidation; no external dependencies - Cache /experiments/:id/calendar?field=X per (experimentId, field). Invalidated immediately on any DailyStatus write. - Cache /experiments/:id/daily-statuses per (experimentId, date, analysisOnly). Invalidated immediately on any DailyStatus write (create/update/delete and analysis-summary saves all clear the relevant prefix). - Add ?analysisOnly=true to /daily-statuses: filters rows where analysis_summary IS NOT NULL. Charts are the only consumer and already discard rows without analysis data; pre-filtering server-side avoids sending the full status payload (71 rows → 1 for this experiment). - ExperimentCalendar: remove allStatuses prop, fetch calendar data directly via API. The component now issues one small GET per field selection change instead of the parent loading thousands of rows upfront. - ExperimentDetail: pass analysisOnly:true to getDailyStatuses; drop allStatuses prop from ExperimentCalendar. Cold experiment page load no longer fetches every daily status record. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
// Lightweight in-process TTL cache with prefix-based invalidation.
|
||||
// Single-process only — suitable for this single-container deployment.
|
||||
|
||||
const DEFAULT_TTL_MS = 10 * 60 * 1000; // 10 minutes
|
||||
|
||||
const store = new Map(); // key → { value, expiresAt }
|
||||
|
||||
function set(key, value, ttlMs = DEFAULT_TTL_MS) {
|
||||
store.set(key, { value, expiresAt: Date.now() + ttlMs });
|
||||
}
|
||||
|
||||
function get(key) {
|
||||
const entry = store.get(key);
|
||||
if (!entry) return undefined;
|
||||
if (Date.now() > entry.expiresAt) {
|
||||
store.delete(key);
|
||||
return undefined;
|
||||
}
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
function del(key) {
|
||||
store.delete(key);
|
||||
}
|
||||
|
||||
// Remove all keys that start with prefix — used to invalidate a whole experiment's worth of cached data.
|
||||
function delByPrefix(prefix) {
|
||||
for (const key of store.keys()) {
|
||||
if (key.startsWith(prefix)) store.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { set, get, del, delByPrefix };
|
||||
Reference in New Issue
Block a user