Files
fusion/packages/engine/src/__tests__/hybrid-executor-gate.test.ts
gsxdsm 6a6c6fdbfd perf(dashboard): speed up startup and eliminate API request storms
Multiple coordinated fixes for the perceived "dashboard takes forever to
load" complaint. Per-page-load HTTP requests drop from ~177 to ~101 and
duplicate per-project InProcessRuntime creation is eliminated.

- engine: shouldUseHybridExecutor no longer auto-enables for local-only
  multi-project setups (set FUSION_HYBRID_EXECUTOR=1 to force). The
  duplicate-runtime path was running self-healing twice per project and
  contending on the same SQLite file. ProjectEngineManager already
  handles N local projects with one InProcessRuntime each.
- dashboard cli: parallelized independent store inits, started
  CentralCore.init early in background, ran plugin loading concurrently
  with extension resolution. Sequenced SQLite store inits to avoid a
  TOCTOU race in addColumnIfMissing migrations across TaskStore /
  AutomationStore / PluginStore / AgentStore (all open the same
  .fusion/fusion.db). Restored try/catch around HybridExecutor.initialize
  and engineManager.ensureEngine so a paused or broken cwd project no
  longer aborts dashboard startup.
- dashboard client: added in-flight request dedupe wrapped around the
  top API offenders. /api/plugins/ui-slots drops from 17x to 1x per load.
  dedupe.forceFresh redirects ALL in-flight waiters to receive the fresh
  post-mutation response, not just the forcing caller. Generation
  counters in useAgents and AgentListModal protect against slow polls
  overwriting fresh state.
- dashboard SSE: agent event handler now debounces 250ms with a
  trailing-edge guard so multi-agent activity bursts coalesce to at
  most 2 refetches per burst.
- dashboard route: PATCH /api/projects/:id with isolationMode change
  returns 503 with actionable guidance when HybridExecutor is
  unavailable, instead of silently persisting a config the live runtime
  won't honor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 21:57:31 -07:00

78 lines
3.0 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import type { CentralCore } from "@fusion/core";
import { shouldUseHybridExecutor } from "../hybrid-executor-gate.js";
function createMockCentralCore(overrides?: {
listNodes?: () => Promise<Array<{ id: string; type: "local" | "remote" }>>;
listProjects?: () => Promise<Array<{ status: "active" | "initializing" | "paused" | "errored" }>>;
}): CentralCore {
return {
listNodes: overrides?.listNodes ?? (async () => [{ id: "local", type: "local" }]),
listProjects: overrides?.listProjects ?? (async () => [{ status: "active" }]),
} as unknown as CentralCore;
}
describe("shouldUseHybridExecutor", () => {
const originalEnv = process.env.FUSION_HYBRID_EXECUTOR;
afterEach(() => {
if (originalEnv === undefined) {
delete process.env.FUSION_HYBRID_EXECUTOR;
} else {
process.env.FUSION_HYBRID_EXECUTOR = originalEnv;
}
});
it("enables via env override=1", async () => {
process.env.FUSION_HYBRID_EXECUTOR = "1";
const decision = await shouldUseHybridExecutor(createMockCentralCore());
expect(decision).toEqual({ enabled: true, reason: "env-override" });
});
it("disables via env override=0", async () => {
process.env.FUSION_HYBRID_EXECUTOR = "0";
const decision = await shouldUseHybridExecutor(createMockCentralCore());
expect(decision).toEqual({ enabled: false, reason: "env-override" });
});
it("enables for multi-node", async () => {
delete process.env.FUSION_HYBRID_EXECUTOR;
const decision = await shouldUseHybridExecutor(
createMockCentralCore({
listNodes: async () => [
{ id: "local", type: "local" },
{ id: "remote", type: "remote" },
],
}),
);
expect(decision).toEqual({ enabled: true, reason: "multi-node" });
});
it("does NOT enable for local-only multi-project (ProjectEngineManager handles it)", async () => {
delete process.env.FUSION_HYBRID_EXECUTOR;
const decision = await shouldUseHybridExecutor(
createMockCentralCore({
listProjects: async () => [{ status: "active" }, { status: "initializing" }],
}),
);
// HybridExecutor's value is cross-node routing. Local-only N-project
// setups don't need it — running it duplicates InProcessRuntime creation.
expect(decision).toEqual({ enabled: false, reason: "single-node-local-only" });
});
it("disables for local-only single-node setup", async () => {
delete process.env.FUSION_HYBRID_EXECUTOR;
const decision = await shouldUseHybridExecutor(createMockCentralCore());
expect(decision).toEqual({ enabled: false, reason: "single-node-local-only" });
});
it("disables when central APIs throw", async () => {
delete process.env.FUSION_HYBRID_EXECUTOR;
const centralCore = createMockCentralCore({
listNodes: vi.fn().mockRejectedValue(new Error("boom")),
});
const decision = await shouldUseHybridExecutor(centralCore);
expect(decision).toEqual({ enabled: false, reason: "central-unavailable" });
});
});