fix: address session-store cache review feedback

This commit is contained in:
Josh Lehman 2026-03-02 13:44:37 -08:00 committed by Peter Steinberger
parent 1212328c8d
commit 175c770171
3 changed files with 26 additions and 26 deletions

View File

@ -18,17 +18,18 @@ export function isCacheEnabled(ttlMs: number): boolean {
return ttlMs > 0;
}
export function getFileMtimeMs(filePath: string): number | undefined {
try {
return fs.statSync(filePath).mtimeMs;
} catch {
return undefined;
}
}
export type FileStatSnapshot = {
mtimeMs: number;
sizeBytes: number;
};
export function getFileSizeBytes(filePath: string): number | undefined {
export function getFileStatSnapshot(filePath: string): FileStatSnapshot | undefined {
try {
return fs.statSync(filePath).size;
const stats = fs.statSync(filePath);
return {
mtimeMs: stats.mtimeMs,
sizeBytes: stats.size,
};
} catch {
return undefined;
}

View File

@ -220,12 +220,12 @@ describe("Session Store Cache", () => {
"session:1": createSessionEntry({ sessionId: "id-1", displayName: "Original" }),
"session:2": createSessionEntry({ sessionId: "id-2", displayName: "Added" }),
};
const preWriteStat = fs.statSync(storePath);
const json2 = JSON.stringify(store2, null, 2);
fs.writeFileSync(storePath, json2);
// Force mtime to match the cached value so only size differs
const stat = fs.statSync(storePath);
fs.utimesSync(storePath, stat.atime, stat.mtime);
fs.utimesSync(storePath, preWriteStat.atime, preWriteStat.mtime);
// The cache should detect the size change and reload from disk
const loaded2 = loadSessionStore(storePath);

View File

@ -17,12 +17,7 @@ import {
normalizeSessionDeliveryFields,
type DeliveryContext,
} from "../../utils/delivery-context.js";
import {
getFileMtimeMs,
getFileSizeBytes,
isCacheEnabled,
resolveCacheTtlMs,
} from "../cache-utils.js";
import { getFileStatSnapshot, isCacheEnabled, resolveCacheTtlMs } from "../cache-utils.js";
import { loadConfig } from "../config.js";
import type { SessionMaintenanceConfig, SessionMaintenanceMode } from "../types.base.js";
import { enforceSessionDiskBudget, type SessionDiskBudgetSweepResult } from "./disk-budget.js";
@ -213,9 +208,11 @@ export function loadSessionStore(
if (!opts.skipCache && isSessionStoreCacheEnabled()) {
const cached = SESSION_STORE_CACHE.get(storePath);
if (cached && isSessionStoreCacheValid(cached)) {
const currentMtimeMs = getFileMtimeMs(storePath);
const currentSizeBytes = getFileSizeBytes(storePath);
if (currentMtimeMs === cached.mtimeMs && currentSizeBytes === cached.sizeBytes) {
const currentFileStat = getFileStatSnapshot(storePath);
if (
currentFileStat?.mtimeMs === cached.mtimeMs &&
currentFileStat?.sizeBytes === cached.sizeBytes
) {
// Return a deep copy to prevent external mutations affecting cache
return structuredClone(cached.store);
}
@ -230,7 +227,8 @@ export function loadSessionStore(
// A short synchronous backoff (50 ms via `Atomics.wait`) is enough for the
// writer to finish.
let store: Record<string, SessionEntry> = {};
let mtimeMs = getFileMtimeMs(storePath);
let fileStat = getFileStatSnapshot(storePath);
let mtimeMs = fileStat?.mtimeMs;
let serializedFromDisk: string | undefined;
const maxReadAttempts = process.platform === "win32" ? 3 : 1;
const retryBuf = maxReadAttempts > 1 ? new Int32Array(new SharedArrayBuffer(4)) : undefined;
@ -247,7 +245,8 @@ export function loadSessionStore(
store = parsed;
serializedFromDisk = raw;
}
mtimeMs = getFileMtimeMs(storePath) ?? mtimeMs;
fileStat = getFileStatSnapshot(storePath) ?? fileStat;
mtimeMs = fileStat?.mtimeMs;
break;
} catch {
// File missing, locked, or transiently corrupt — retry on Windows.
@ -295,7 +294,7 @@ export function loadSessionStore(
loadedAt: Date.now(),
storePath,
mtimeMs,
sizeBytes: getFileSizeBytes(storePath),
sizeBytes: fileStat?.sizeBytes,
serialized: serializedFromDisk,
});
}
@ -664,7 +663,7 @@ function updateSessionStoreWriteCaches(params: {
store: Record<string, SessionEntry>;
serialized: string;
}): void {
const mtimeMs = getFileMtimeMs(params.storePath);
const fileStat = getFileStatSnapshot(params.storePath);
SESSION_STORE_SERIALIZED_CACHE.set(params.storePath, params.serialized);
if (!isSessionStoreCacheEnabled()) {
SESSION_STORE_CACHE.delete(params.storePath);
@ -674,8 +673,8 @@ function updateSessionStoreWriteCaches(params: {
store: structuredClone(params.store),
loadedAt: Date.now(),
storePath: params.storePath,
mtimeMs,
sizeBytes: getFileSizeBytes(params.storePath),
mtimeMs: fileStat?.mtimeMs,
sizeBytes: fileStat?.sizeBytes,
serialized: params.serialized,
});
}