Anton Malykhin
feat: optimize bucket data caching and document refresh behavior
a290b8b
Raw
History Blame Contribute Delete
4.21 kB
import { env } from '$env/dynamic/private';
import type { BucketDataState } from '$lib/types/bucket-state';
import type { ToolsDataset } from '$lib/types/tools-data';
import { adaptBucketTools } from './adapt-tools';
import { emptyToolsDataset } from './fallback-data';
import { toPublicBucketError } from './public-error';
import { fetchBucketRankingSnapshot } from './ranking-snapshot';
import { fetchBucketVisualizationSnapshot } from './tools-snapshot';
import type { BucketVisualizationSnapshot } from './types';
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
let cached:
{ value: BucketVisualizationSnapshot; snapshotId: string; expiresAt: number } | undefined;
let adaptedCached: { value: ToolsDataset; snapshotId: string } | undefined;
let inFlight: Promise<BucketVisualizationSnapshot> | undefined;
function cacheTtlMs() {
const configured = Number(env.HF_BUCKET_CACHE_TTL_MS);
return Number.isInteger(configured) && configured > 0 ? configured : DEFAULT_CACHE_TTL_MS;
}
async function refreshToolsSnapshot() {
const rankingSnapshot = await fetchBucketRankingSnapshot({ refreshManifest: true });
if (cached?.snapshotId === rankingSnapshot.manifest.snapshot_id) {
cached.expiresAt = Date.now() + cacheTtlMs();
return cached.value;
}
const value = await fetchBucketVisualizationSnapshot(rankingSnapshot);
cached = {
value,
snapshotId: rankingSnapshot.manifest.snapshot_id,
expiresAt: Date.now() + cacheTtlMs()
};
return value;
}
export async function getHfBucketToolsSnapshot() {
if (cached && cached.expiresAt > Date.now()) return cached.value;
if (!inFlight) {
inFlight = refreshToolsSnapshot().finally(() => {
inFlight = undefined;
});
}
try {
return await inFlight;
} catch (error) {
if (cached) {
console.warn(
'[hf-bucket] Serving stale Tools visualization data after refresh failure.',
error
);
return cached.value;
}
throw error;
}
}
async function getHfBucketToolsSnapshotState(): Promise<
BucketDataState<BucketVisualizationSnapshot>
> {
if (!inFlight) {
inFlight = refreshToolsSnapshot().finally(() => {
inFlight = undefined;
});
}
try {
return {
status: 'ok',
source: 'remote',
data: await inFlight
};
} catch (error) {
if (cached) {
console.warn(
'[hf-bucket] Serving stale Tools visualization data after refresh failure.',
error
);
return {
status: 'stale',
source: 'stale',
data: cached.value,
error: toPublicBucketError(error)
};
}
console.error('[hf-bucket] Tools visualization data is unavailable.', error);
return {
status: 'unavailable',
source: 'unavailable',
data: emptyToolsDataset() as unknown as BucketVisualizationSnapshot,
error: toPublicBucketError(error)
};
}
}
export async function getHfBucketTools(): Promise<ToolsDataset> {
const state = await getHfBucketToolsState();
if (state.status === 'unavailable') throw new Error(state.error.message);
return state.data;
}
export async function getHfBucketToolsState(): Promise<BucketDataState<ToolsDataset>> {
const snapshotState = await getHfBucketToolsSnapshotState();
if (snapshotState.status === 'unavailable') {
return {
...snapshotState,
data: emptyToolsDataset()
};
}
try {
const snapshotId = snapshotState.data.manifest.snapshot_id;
const data =
adaptedCached?.snapshotId === snapshotId
? adaptedCached.value
: adaptBucketTools(snapshotState.data);
adaptedCached = { value: data, snapshotId };
if (snapshotState.status === 'stale') {
return {
status: 'stale',
source: 'stale',
data,
error: snapshotState.error
};
}
return {
status: 'ok',
source: snapshotState.source,
data
};
} catch (error) {
if (cached) {
console.warn(
'[hf-bucket] Serving stale Tools visualization data after adapt failure.',
error
);
return {
status: 'stale',
source: 'stale',
data: adaptBucketTools(cached.value),
error: toPublicBucketError(error)
};
}
console.error('[hf-bucket] Tools visualization data is unavailable.', error);
return {
status: 'unavailable',
source: 'unavailable',
data: emptyToolsDataset(),
error: toPublicBucketError(error)
};
}
}