Merge pull request #1598 from pikasTech/fix/1585-terminal-trace-cache
[P0] Workbench terminal trace 纯读缓存,降低长 trace 重复 GET 延迟
This commit is contained in:
@@ -183,8 +183,10 @@ test("workbench read model recovers trace events from durable projection without
|
||||
async ensureBootstrap() {},
|
||||
async authenticate() { return { ok: true, actor: ACTOR, session: { id: "uss_workbench_reader" } }; }
|
||||
};
|
||||
let traceQueryCount = 0;
|
||||
const runtimeStore = {
|
||||
async queryAgentTraceEvents(params = {}) {
|
||||
traceQueryCount += 1;
|
||||
assert.equal(params.traceId, traceId);
|
||||
return { events: durableEvents, count: durableEvents.length };
|
||||
}
|
||||
@@ -210,6 +212,7 @@ test("workbench read model recovers trace events from durable projection without
|
||||
assert.equal(trace.body.events.length, 2);
|
||||
assert.equal(trace.body.traceStatus, "completed");
|
||||
assert.equal(trace.body.hasMore, false);
|
||||
assert.equal(traceQueryCount, 1);
|
||||
} finally {
|
||||
await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import { defaultCodeAgentTraceStore } from "./code-agent-trace-store.ts";
|
||||
import { safeConversationId, safeSessionId, safeTraceId } from "./server-http-utils.ts";
|
||||
import { durableTraceStatus, normalizeWorkbenchStatus, TERMINAL_STATUSES, traceTerminalEvidence } from "./workbench-turn-projection.ts";
|
||||
|
||||
const TERMINAL_DURABLE_TRACE_CACHE_MAX = 256;
|
||||
const terminalDurableTraceCache = new Map();
|
||||
|
||||
export function createWorkbenchFactsStore(options = {}, actor = null) {
|
||||
const accessStore = options.accessController?.store ?? options.accessController ?? null;
|
||||
const traceStore = options.traceStore ?? defaultCodeAgentTraceStore;
|
||||
@@ -101,21 +104,29 @@ export function createWorkbenchFactsStore(options = {}, actor = null) {
|
||||
|
||||
async function durableTraceSnapshot(runtimeStore, traceId) {
|
||||
if (!runtimeStore || typeof runtimeStore.queryAgentTraceEvents !== "function") return null;
|
||||
const safeId = safeTraceId(traceId);
|
||||
if (!safeId) return null;
|
||||
const cached = terminalDurableTraceCache.get(safeId);
|
||||
if (cached) {
|
||||
terminalDurableTraceCache.delete(safeId);
|
||||
terminalDurableTraceCache.set(safeId, cached);
|
||||
return cached;
|
||||
}
|
||||
let result;
|
||||
try {
|
||||
result = await runtimeStore.queryAgentTraceEvents({ traceId });
|
||||
result = await runtimeStore.queryAgentTraceEvents({ traceId: safeId });
|
||||
} catch (error) {
|
||||
return projectionStoreUnavailableTrace(traceId, error);
|
||||
return projectionStoreUnavailableTrace(safeId, error);
|
||||
}
|
||||
const events = Array.isArray(result?.events) ? result.events : [];
|
||||
if (events.length === 0) return null;
|
||||
const normalizedEvents = events.map((event, index) => ({ ...event, traceId, seq: eventSeq(event, index) }));
|
||||
const normalizedEvents = events.map((event, index) => ({ ...event, traceId: safeId, seq: eventSeq(event, index) }));
|
||||
const firstEvent = normalizedEvents[0] ?? null;
|
||||
const lastEvent = normalizedEvents.at(-1) ?? null;
|
||||
const status = durableTraceStatus(normalizedEvents);
|
||||
const terminalEvidence = traceTerminalEvidence({ events: normalizedEvents, status });
|
||||
return {
|
||||
traceId,
|
||||
const snapshot = {
|
||||
traceId: safeId,
|
||||
status,
|
||||
createdAt: firstEvent?.createdAt ?? null,
|
||||
updatedAt: lastEvent?.createdAt ?? firstEvent?.createdAt ?? null,
|
||||
@@ -130,6 +141,19 @@ async function durableTraceSnapshot(runtimeStore, traceId) {
|
||||
outputTruncated: normalizedEvents.some((event) => event.outputTruncated === true),
|
||||
valuesPrinted: false
|
||||
};
|
||||
rememberTerminalDurableTrace(snapshot);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
function rememberTerminalDurableTrace(snapshot) {
|
||||
const traceId = safeTraceId(snapshot?.traceId);
|
||||
if (!traceId || !TERMINAL_STATUSES.has(normalizeStatus(snapshot?.status))) return;
|
||||
terminalDurableTraceCache.delete(traceId);
|
||||
terminalDurableTraceCache.set(traceId, snapshot);
|
||||
while (terminalDurableTraceCache.size > TERMINAL_DURABLE_TRACE_CACHE_MAX) {
|
||||
const oldest = terminalDurableTraceCache.keys().next().value;
|
||||
terminalDurableTraceCache.delete(oldest);
|
||||
}
|
||||
}
|
||||
|
||||
function projectionStoreUnavailableTrace(traceId, error) {
|
||||
|
||||
Reference in New Issue
Block a user