Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/app/api/series/[slug]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { unstable_cache } from "next/cache";
import { getBenchmark } from "@/data/benchmarks";
import { filterSig, loadSpecsUncached, specToBenchmark } from "@/lib/materialize/load";
import { readMaterialized } from "@/lib/materialize/store";
import { loadSnapshotFromBlob } from "@/lib/bench-blob";
import { buildProviderColors } from "@/lib/series-colors";
import { logoPath } from "@/lib/logo-manifest";
import { clientKey, rateLimit, tooManyRequests } from "@/lib/rate-limit";
Expand Down Expand Up @@ -32,7 +33,10 @@ const getSeriesMapCached = unstable_cache(
venue: string | undefined,
): Promise<Record<string, (number | null)[]> | null> => {
const sig = filterSig({ chain, region, kind, venue });
const stored = await readMaterialized(slug, sig);
// Try CDN blob first (Phase 3), fall back to Redis via SRH.
const stored =
(await loadSnapshotFromBlob(slug, sig)) ??
(await readMaterialized(slug, sig));
if (stored) {
const fromBlob =
range === "7d"
Expand Down
35 changes: 35 additions & 0 deletions src/lib/bench-blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
*/

import type { Benchmark } from "@/types/benchmark";
import {
MAT_SCHEMA_VERSION,
type MaterializedSnapshot,
} from "@/lib/materialize/schema";

const DEFAULT_BASE_URL = "https://kv.openchainbench.com/aggregate";
const FETCH_TIMEOUT_MS = 5_000;
Expand Down Expand Up @@ -90,3 +94,34 @@ export async function loadVariantFromBlob(
if (env.sig !== sig) return null;
return env.bench;
}

/**
* Snapshot-shaped adapter for callers that expect the exact
* `readMaterialized` return value. Lets `readMaterialized(slug, sig)`
* call sites become `loadSnapshotFromBlob(slug, sig) ?? readMaterialized(slug, sig)`
* with zero downstream code change. `state` is stubbed empty because
* the blob broadcast doesn't include ring-buffer state (worker-internal,
* never read by the site — only the aggregation loop uses it).
*/
export async function loadSnapshotFromBlob(
slug: string,
sig: string,
): Promise<MaterializedSnapshot | null> {
const url = sig
? `${baseUrl()}/variants/${encodeURIComponent(slug)}/${encodeURIComponent(sig)}.json`
: `${baseUrl()}/benches/${encodeURIComponent(slug)}.json`;
const raw = await fetchJson(url);
if (!isBenchEnvelope(raw) || raw.v !== 1 || raw.slug !== slug) return null;
if (sig) {
const env = raw as VariantEnvelope;
if (env.sig !== sig) return null;
}
return {
v: MAT_SCHEMA_VERSION,
slug,
sig,
builtAt: raw.builtAt,
bench: raw.bench,
state: { providers: {}, rings: {} },
};
}
17 changes: 13 additions & 4 deletions src/lib/rpc-hub-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from "@/lib/materialize/load";
import { REMOVED_BENCH_SLUGS } from "@/lib/removed-benches";
import { readMaterialized, storeConfigured } from "@/lib/materialize/store";
import { loadSnapshotFromBlob } from "@/lib/bench-blob";
import { chainLabelForSlug } from "@/lib/chains";
import { matchesChainSlug } from "@/lib/chain-aliases";
import type { Benchmark, ProviderResult } from "@/types/benchmark";
Expand Down Expand Up @@ -173,7 +174,10 @@ function liveRows(bench: Benchmark): ProviderResult[] {
}

async function buildChain(spec: Spec): Promise<RpcHubChain | null> {
const snap = await readMaterialized(spec.slug, "");
// Try CDN blob first (Phase 3), fall back to Redis via SRH.
const snap =
(await loadSnapshotFromBlob(spec.slug, "")) ??
(await readMaterialized(spec.slug, ""));
if (!snap) return null;
const bench = snap.bench;
const rows = liveRows(bench);
Expand All @@ -193,9 +197,14 @@ async function buildChain(spec: Spec): Promise<RpcHubChain | null> {
}
}
const variantSnaps = await Promise.all(
RPC_REGION_KEYS.map((region) =>
readMaterialized(spec.slug, filterSig({ region })).catch(() => null),
),
RPC_REGION_KEYS.map(async (region) => {
const sig = filterSig({ region });
// Try CDN blob first, fall back to Redis via SRH.
return (
(await loadSnapshotFromBlob(spec.slug, sig).catch(() => null)) ??
(await readMaterialized(spec.slug, sig).catch(() => null))
);
}),
);
for (let i = 0; i < RPC_REGION_KEYS.length; i++) {
const region = RPC_REGION_KEYS[i];
Expand Down
6 changes: 5 additions & 1 deletion src/lib/search-featured.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import { getBenchmarks } from "@/data/benchmarks";
import { readMaterialized } from "@/lib/materialize/store";
import { loadSnapshotFromBlob } from "@/lib/bench-blob";
import { leader, fieldValue } from "@/lib/citation";

const FEATURED_BENCH_SLUGS = [
Expand Down Expand Up @@ -104,7 +105,10 @@ export async function buildFeaturedLeadersFromStore(): Promise<FeaturedLeadersBl
const snapshots = await Promise.all(
ALL_SLUGS.map(async (slug) => {
try {
const snap = await readMaterialized(slug, "");
// Try CDN blob first (Phase 3), fall back to Redis via SRH.
const snap =
(await loadSnapshotFromBlob(slug, "")) ??
(await readMaterialized(slug, ""));
return snap ? snap.bench : null;
} catch {
return null;
Expand Down
Loading