perf(dashboard): cache gh CLI checks and defer SQLite integrity scan
Cold-start dashboard responsiveness went from ~99s to ~6-11s. CPU profiling identified two synchronous-spawn hotspots blocking the event loop: - `GitHubTrackingReconciler` scanned up to 200 done tasks per startup, each call into `getIssue` invoking `isGhAvailable()` + `isGhAuthenticated()` via `execFileSync`. `gh auth status` makes a network roundtrip, so 400 sync spawns ≈ 71s of pure event-loop blocking (69% of cold-start CPU). Memoized both checks with a 60s TTL; `resetGhAvailabilityCache()` is exported for login/logout flows that need immediate invalidation. - `PRAGMA integrity_check(100)` walks every page of the SQLite file (~7s per database, multiple DBs × projects). The deferred check was scheduled 3s after init — right in the responsiveness-critical window. Pushed to 60s so the user is already interacting before it runs; check itself is unchanged. Also yields the event loop between major InProcessRuntime init phases and between self-healing recovery steps (34 per project), defers orphan-task AI agent resumption by 30s (env-overridable, auto-zero under Vitest), and ships an opt-in `FUSION_TRACE_EL_LAG=/path/to/file` event-loop lag tracer that diagnosed all of the above. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
"@runfusion/fusion": patch
|
||||
"@fusion/dashboard": patch
|
||||
"@fusion/engine": patch
|
||||
"@fusion/core": patch
|
||||
---
|
||||
|
||||
Dashboard startup and request-storm fixes:
|
||||
@@ -13,3 +14,9 @@ Dashboard startup and request-storm fixes:
|
||||
- **Live isolation-mode transition**: PATCH `/api/projects/:id` with an `isolationMode` change now returns a 503 with actionable guidance when HybridExecutor is unavailable (local-only single-node), instead of silently persisting a config that the live runtime won't honor.
|
||||
- **Error handling regression**: restored try/catch around `HybridExecutor.initialize` and `engineManager.ensureEngine` in the parallel engine setup so a paused or broken cwd project no longer aborts dashboard startup.
|
||||
- **TaskStore migration race**: sequenced the SQLite store inits (TaskStore → AutomationStore → PluginStore → AgentStore) since they all open the same `.fusion/fusion.db` and run `addColumnIfMissing` migrations with a TOCTOU `hasColumn` → `ALTER` pattern.
|
||||
- **`gh` CLI invocation storm**: `isGhAvailable()` and `isGhAuthenticated()` now memoize their results with a 60s TTL. `GitHubTrackingReconciler` was scanning up to 200 done tasks at startup and calling `hasGhAuth()` per task — each call shelled out to `gh --version` and `gh auth status` (which makes a network roundtrip), pinning the event loop for ~60s of synchronous `spawnSync` work. CPU-profile-confirmed: dropped from 71s (69% of cold-start CPU) to 2s. The cache benefits all 28+ call sites in `dashboard/src/github.ts`, the engine PR monitor, the research provider, and the API routes automatically. `resetGhAvailabilityCache()` is exported for login/logout flows that need to invalidate immediately.
|
||||
- **SQLite integrity check delay**: `PRAGMA integrity_check(100)` walks every page of the database file and was scheduled 3 seconds after init — landing right in the responsiveness-critical window for ~7s per database. Pushed the deferred-check timer to 60 seconds so the user is already interacting with the dashboard by the time it runs. The check itself is unchanged; corruption detection still works.
|
||||
- **Engine init event-loop yields**: `InProcessRuntime.start()` now awaits a `setImmediate`-based yield between major init phases (TaskStore → Plugins → WorktreePool → AgentStore → Scheduler → Executor → HeartbeatMonitor → SelfHealing) so HTTP requests can be processed between them instead of waiting on the entire stack. Same yield is now interleaved between each step of `SelfHealingManager.runStartupRecovery()` (34 steps per project) and its periodic maintenance batches.
|
||||
- **Deferred startup recovery**: `InProcessRuntime.start()` no longer awaits `resumeStartupRecoverySequence()` or `workerManager.reconcileOrphaned()` — both are correctness-preserving background operations and their git/SQLite work was blocking server-listen for several seconds.
|
||||
- **Deferred orphan-task AI agent resumption**: orphaned in-progress tasks resumed at engine restart now wait 30 seconds before spawning their AI agent session (worktree setup + pi-coding-agent session creation is heavy and saturates the event loop). Override via `FUSION_RESUME_ORPHAN_DELAY_MS=<ms>`; auto-zeroes under Vitest.
|
||||
- **Event-loop lag tracer**: opt-in debug aid for diagnosing cold-start regressions. Set `FUSION_TRACE_EL_LAG=/path/to/file.txt` to capture every block >150ms with a timestamp relative to process start.
|
||||
|
||||
Reference in New Issue
Block a user