

























@@ -53,6 +53,65 @@ function createMaintenanceTimerDeps() {
5353};
5454}
555556+type MaintenanceTimerDeps = ReturnType<typeof createMaintenanceTimerDeps>;
57+58+function staleRunTimestamp(): number {
59+return Date.now() - ABORTED_RUN_TTL_MS - 1;
60+}
61+62+function seedStaleRunBuffers(deps: MaintenanceTimerDeps, runId: string): void {
63+deps.chatRunBuffers.set(runId, "buffer");
64+deps.chatRunState.rawBuffers.set(runId, "raw buffer");
65+deps.chatRunState.bufferUpdatedAt.set(runId, staleRunTimestamp());
66+deps.chatDeltaSentAt.set(runId, staleRunTimestamp());
67+deps.chatDeltaLastBroadcastLen.set(runId, 6);
68+deps.chatRunState.deltaLastBroadcastText.set(runId, "buffer");
69+}
70+71+function expectStaleRunBuffersPresent(deps: MaintenanceTimerDeps, runId: string): void {
72+expect(deps.chatRunBuffers.get(runId)).toBe("buffer");
73+expect(deps.chatRunState.rawBuffers.get(runId)).toBe("raw buffer");
74+expect(deps.chatRunState.bufferUpdatedAt.has(runId)).toBe(true);
75+expect(deps.chatDeltaSentAt.has(runId)).toBe(true);
76+expect(deps.chatDeltaLastBroadcastLen.get(runId)).toBe(6);
77+expect(deps.chatRunState.deltaLastBroadcastText.get(runId)).toBe("buffer");
78+}
79+80+function expectStaleRunBuffersSwept(deps: MaintenanceTimerDeps, runId: string): void {
81+expect(deps.chatRunBuffers.has(runId)).toBe(false);
82+expect(deps.chatRunState.rawBuffers.has(runId)).toBe(false);
83+expect(deps.chatRunState.bufferUpdatedAt.has(runId)).toBe(false);
84+expect(deps.chatDeltaSentAt.has(runId)).toBe(false);
85+expect(deps.chatDeltaLastBroadcastLen.has(runId)).toBe(false);
86+expect(deps.chatRunState.deltaLastBroadcastText.has(runId)).toBe(false);
87+}
88+89+function seedBufferedAgentEvent(deps: MaintenanceTimerDeps, key: string, runId = key): void {
90+deps.chatRunState.bufferedAgentEvents.set(key, {
91+payload: {
92+ runId,
93+seq: 1,
94+stream: "assistant",
95+ts: Date.now(),
96+data: { text: "buffer", delta: "buffer" },
97+},
98+});
99+}
100+101+function seedStableDedupeEntries(deps: MaintenanceTimerDeps, now: number): void {
102+for (let index = 0; index < DEDUPE_MAX; index += 1) {
103+deps.dedupe.set(`stable-${index}`, { ts: now - 1_000 + index, ok: true });
104+}
105+}
106+107+async function createTimedMaintenanceScenario() {
108+vi.useFakeTimers();
109+vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
110+const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
111+const deps = createMaintenanceTimerDeps();
112+return { startGatewayMaintenanceTimers, deps, now: Date.now() };
113+}
114+56115function stopMaintenanceTimers(timers: {
57116tickInterval: NodeJS.Timeout;
58117healthInterval: NodeJS.Timeout;
@@ -189,23 +248,13 @@ describe("startGatewayMaintenanceTimers", () => {
189248const deps = createMaintenanceTimerDeps();
190249const runId = "run-active";
191250deps.chatAbortControllers.set(runId, createActiveRun("main"));
192-deps.chatRunBuffers.set(runId, "buffer");
193-deps.chatRunState.rawBuffers.set(runId, "raw buffer");
194-deps.chatRunState.bufferUpdatedAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
195-deps.chatDeltaSentAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
196-deps.chatDeltaLastBroadcastLen.set(runId, 6);
197-deps.chatRunState.deltaLastBroadcastText.set(runId, "buffer");
251+seedStaleRunBuffers(deps, runId);
198252199253const timers = startGatewayMaintenanceTimers(deps);
200254201255await vi.advanceTimersByTimeAsync(60_000);
202256203-expect(deps.chatRunBuffers.get(runId)).toBe("buffer");
204-expect(deps.chatRunState.rawBuffers.get(runId)).toBe("raw buffer");
205-expect(deps.chatRunState.bufferUpdatedAt.has(runId)).toBe(true);
206-expect(deps.chatDeltaSentAt.has(runId)).toBe(true);
207-expect(deps.chatDeltaLastBroadcastLen.get(runId)).toBe(6);
208-expect(deps.chatRunState.deltaLastBroadcastText.get(runId)).toBe("buffer");
257+expectStaleRunBuffersPresent(deps, runId);
209258210259stopMaintenanceTimers(timers);
211260});
@@ -216,23 +265,13 @@ describe("startGatewayMaintenanceTimers", () => {
216265const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
217266const deps = createMaintenanceTimerDeps();
218267const runId = "run-orphaned";
219-deps.chatRunBuffers.set(runId, "buffer");
220-deps.chatRunState.rawBuffers.set(runId, "raw buffer");
221-deps.chatRunState.bufferUpdatedAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
222-deps.chatDeltaSentAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
223-deps.chatDeltaLastBroadcastLen.set(runId, 6);
224-deps.chatRunState.deltaLastBroadcastText.set(runId, "buffer");
268+seedStaleRunBuffers(deps, runId);
225269226270const timers = startGatewayMaintenanceTimers(deps);
227271228272await vi.advanceTimersByTimeAsync(60_000);
229273230-expect(deps.chatRunBuffers.has(runId)).toBe(false);
231-expect(deps.chatRunState.rawBuffers.has(runId)).toBe(false);
232-expect(deps.chatRunState.bufferUpdatedAt.has(runId)).toBe(false);
233-expect(deps.chatDeltaSentAt.has(runId)).toBe(false);
234-expect(deps.chatDeltaLastBroadcastLen.has(runId)).toBe(false);
235-expect(deps.chatRunState.deltaLastBroadcastText.has(runId)).toBe(false);
274+expectStaleRunBuffersSwept(deps, runId);
236275237276stopMaintenanceTimers(timers);
238277});
@@ -244,16 +283,8 @@ describe("startGatewayMaintenanceTimers", () => {
244283const deps = createMaintenanceTimerDeps();
245284const runId = "run-agent-orphaned";
246285const throttleKey = `${runId}:assistant`;
247-deps.chatRunState.agentDeltaSentAt.set(throttleKey, Date.now() - ABORTED_RUN_TTL_MS - 1);
248-deps.chatRunState.bufferedAgentEvents.set(throttleKey, {
249-payload: {
250- runId,
251-seq: 1,
252-stream: "assistant",
253-ts: Date.now(),
254-data: { text: "buffer", delta: "buffer" },
255-},
256-});
286+deps.chatRunState.agentDeltaSentAt.set(throttleKey, staleRunTimestamp());
287+seedBufferedAgentEvent(deps, throttleKey, runId);
257288258289const timers = startGatewayMaintenanceTimers(deps);
259290@@ -273,35 +304,17 @@ describe("startGatewayMaintenanceTimers", () => {
273304const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
274305const deps = createMaintenanceTimerDeps();
275306const runId = "run-aborted";
276-deps.chatRunState.abortedRuns.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
277-deps.chatRunBuffers.set(runId, "buffer");
278-deps.chatRunState.rawBuffers.set(runId, "raw buffer");
279-deps.chatRunState.bufferUpdatedAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
280-deps.chatDeltaSentAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
281-deps.chatDeltaLastBroadcastLen.set(runId, 6);
282-deps.chatRunState.deltaLastBroadcastText.set(runId, "buffer");
283-deps.chatRunState.agentDeltaSentAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
284-deps.chatRunState.bufferedAgentEvents.set(runId, {
285-payload: {
286- runId,
287-seq: 1,
288-stream: "assistant",
289-ts: Date.now(),
290-data: { text: "buffer", delta: "buffer" },
291-},
292-});
307+deps.chatRunState.abortedRuns.set(runId, staleRunTimestamp());
308+seedStaleRunBuffers(deps, runId);
309+deps.chatRunState.agentDeltaSentAt.set(runId, staleRunTimestamp());
310+seedBufferedAgentEvent(deps, runId);
293311294312const timers = startGatewayMaintenanceTimers(deps);
295313296314await vi.advanceTimersByTimeAsync(60_000);
297315298316expect(deps.chatRunState.abortedRuns.has(runId)).toBe(false);
299-expect(deps.chatRunBuffers.has(runId)).toBe(false);
300-expect(deps.chatRunState.rawBuffers.has(runId)).toBe(false);
301-expect(deps.chatRunState.bufferUpdatedAt.has(runId)).toBe(false);
302-expect(deps.chatDeltaSentAt.has(runId)).toBe(false);
303-expect(deps.chatDeltaLastBroadcastLen.has(runId)).toBe(false);
304-expect(deps.chatRunState.deltaLastBroadcastText.has(runId)).toBe(false);
317+expectStaleRunBuffersSwept(deps, runId);
305318expect(deps.chatRunState.agentDeltaSentAt.has(runId)).toBe(false);
306319expect(deps.chatRunState.bufferedAgentEvents.has(runId)).toBe(false);
307320@@ -315,7 +328,7 @@ describe("startGatewayMaintenanceTimers", () => {
315328const deps = createMaintenanceTimerDeps();
316329const runId = "run-raw-only";
317330deps.chatRunState.rawBuffers.set(runId, "suppressed raw buffer");
318-deps.chatRunState.bufferUpdatedAt.set(runId, Date.now() - ABORTED_RUN_TTL_MS - 1);
331+deps.chatRunState.bufferUpdatedAt.set(runId, staleRunTimestamp());
319332deps.chatRunState.deltaLastBroadcastText.set(runId, "suppressed raw buffer");
320333321334const timers = startGatewayMaintenanceTimers(deps);
@@ -330,11 +343,7 @@ describe("startGatewayMaintenanceTimers", () => {
330343});
331344332345it("keeps active agent dedupe entries past the normal ttl", async () => {
333-vi.useFakeTimers();
334-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
335-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
336-const deps = createMaintenanceTimerDeps();
337-const now = Date.now();
346+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
338347deps.chatAbortControllers.set("active-agent", createActiveRun("agent:main:main", "agent"));
339348deps.dedupe.set("agent:active-agent", {
340349ts: now - DEDUPE_TTL_MS - 1,
@@ -358,11 +367,7 @@ describe("startGatewayMaintenanceTimers", () => {
358367});
359368360369it("keeps pending accepted agent dedupe entries until their run expiry", async () => {
361-vi.useFakeTimers();
362-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
363-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
364-const deps = createMaintenanceTimerDeps();
365-const now = Date.now();
370+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
366371deps.dedupe.set("agent:pending-agent", {
367372ts: now - DEDUPE_TTL_MS - 1,
368373ok: true,
@@ -395,11 +400,7 @@ describe("startGatewayMaintenanceTimers", () => {
395400});
396401397402it("evicts pending accepted agent dedupe entries with invalid run expiry", async () => {
398-vi.useFakeTimers();
399-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
400-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
401-const deps = createMaintenanceTimerDeps();
402-const now = Date.now();
403+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
403404deps.dedupe.set("agent:invalid-expiry-pending-agent", {
404405ts: now - DEDUPE_TTL_MS - 1,
405406ok: true,
@@ -441,11 +442,7 @@ describe("startGatewayMaintenanceTimers", () => {
441442});
442443443444it("keeps active exec approval dedupe aliases past the normal ttl", async () => {
444-vi.useFakeTimers();
445-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
446-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
447-const deps = createMaintenanceTimerDeps();
448-const now = Date.now();
445+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
449446const runId = "exec-approval-followup:req-active:nonce:retry-1";
450447deps.chatAbortControllers.set(runId, createActiveRun("agent:main:main", "agent"));
451448deps.dedupe.set("agent:exec-approval-followup:req-active", {
@@ -470,15 +467,9 @@ describe("startGatewayMaintenanceTimers", () => {
470467});
471468472469it("evicts dedupe overflow by oldest timestamp even after reinsertion", async () => {
473-vi.useFakeTimers();
474-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
475-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
476-const deps = createMaintenanceTimerDeps();
477-const now = Date.now();
470+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
478471479-for (let index = 0; index < DEDUPE_MAX; index += 1) {
480-deps.dedupe.set(`stable-${index}`, { ts: now - 1_000 + index, ok: true });
481-}
472+seedStableDedupeEntries(deps, now);
482473483474deps.dedupe.delete("stable-10");
484475deps.dedupe.set("stable-10", { ts: now - 2_000, ok: true });
@@ -553,15 +544,9 @@ describe("startGatewayMaintenanceTimers", () => {
553544});
554545555546it("does not evict active agent dedupe entries while trimming overflow", async () => {
556-vi.useFakeTimers();
557-vi.setSystemTime(new Date("2026-03-22T00:00:00Z"));
558-const { startGatewayMaintenanceTimers } = await import("./server-maintenance.js");
559-const deps = createMaintenanceTimerDeps();
560-const now = Date.now();
547+const { startGatewayMaintenanceTimers, deps, now } = await createTimedMaintenanceScenario();
561548562-for (let index = 0; index < DEDUPE_MAX; index += 1) {
563-deps.dedupe.set(`stable-${index}`, { ts: now - 1_000 + index, ok: true });
564-}
549+seedStableDedupeEntries(deps, now);
565550deps.chatAbortControllers.set("active-oldest", createActiveRun("agent:main:main", "agent"));
566551deps.dedupe.set("agent:active-oldest", {
567552ts: now - 10_000,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。