phase-8f: persistant cache locally

This commit is contained in:
Kazuma
2026-06-05 22:52:30 -04:00
parent bd373ab69b
commit 9fb3808eb5
7 changed files with 551 additions and 24 deletions
+34 -2
View File
@@ -1,9 +1,16 @@
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { YahooFinanceClient } from '../clients/YahooFinanceClient';
import { REGIME } from '../config/constants';
import type { MarketContext, Logger, BenchmarkProviderOptions } from '../types';
interface CacheFile {
data: MarketContext;
expiresAt: number;
}
export class BenchmarkProvider {
private static readonly TTL_MS = 60 * 60 * 1000;
private static readonly CACHE_PATH = '.benchmark-cache.json';
private static readonly DEFAULTS: MarketContext = {
sp500Price: 5000,
@@ -32,10 +39,33 @@ export class BenchmarkProvider {
private readonly client: YahooFinanceClient,
{ logger }: BenchmarkProviderOptions = {},
) {
this.cache = { data: null, expiresAt: 0 };
this.cache = this.loadDiskCache();
this.logger = logger ?? (console as unknown as Logger);
}
private loadDiskCache(): { data: MarketContext | null; expiresAt: number } {
try {
if (!existsSync(BenchmarkProvider.CACHE_PATH)) return { data: null, expiresAt: 0 };
const file = JSON.parse(readFileSync(BenchmarkProvider.CACHE_PATH, 'utf8')) as CacheFile;
if (Date.now() < file.expiresAt) return { data: file.data, expiresAt: file.expiresAt };
} catch {
// corrupt or missing — ignore
}
return { data: null, expiresAt: 0 };
}
private saveDiskCache(data: MarketContext, expiresAt: number): void {
try {
writeFileSync(
BenchmarkProvider.CACHE_PATH,
JSON.stringify({ data, expiresAt } satisfies CacheFile, null, 2),
'utf8',
);
} catch {
// non-fatal — in-memory cache still works
}
}
async getMarketContext(): Promise<MarketContext> {
if (this.cache.data && Date.now() < this.cache.expiresAt) return this.cache.data;
@@ -75,7 +105,9 @@ export class BenchmarkProvider {
},
};
this.cache = { data: context, expiresAt: Date.now() + BenchmarkProvider.TTL_MS };
const expiresAt = Date.now() + BenchmarkProvider.TTL_MS;
this.cache = { data: context, expiresAt };
this.saveDiskCache(context, expiresAt);
return context;
} catch (err) {
this.logger.warn('Market data fetch failed, using defaults:', (err as Error).message);