Files
openchamber/packages/ui/src/sync/session-load-performance.ts
T
𝖎𝖚𝖑𝖎𝖎𝖆andBohdan Triapitsyn aae889b904 perf: optimize session loading and desktop startup (#2545)
* perf: optimize session loading and startup

* fix(chat): stabilize history prepend virtualization

* perf: unblock first session open from startup network contention

Opening the first session after app start waited seconds for its message
fetch. Three independent contributors, each measured via CDP network
capture and Chromium net-log against the packaged desktop app:

- The active-session watchdog fired an uncapped per-directory status poll
  and child-session discovery burst at startup, and other subsystems
  (git checks, global session pages, command/skill discovery) fanned out
  alongside it, saturating the browser's ~6 HTTP/1.1 sockets per origin.
  Add a shared background-network gate (concurrency 3) and route the
  watchdog, poll-shaped git reads (also priority: low), global session
  pages, command/skill loads, and the background update check through it.

- The packaged renderer is cross-origin to the loopback backend, so every
  API call needs a CORS preflight; a few slow OpenCode-proxied requests
  held the whole pool while preflights and interactive traffic queued
  behind them. Lift Chromium's per-host connection cap for loopback via
  ignore-connections-limit in the Electron shell.

- OpenCode initializes each directory lazily on its first request, so the
  first click paid that cost interactively. Warm the last-used directory
  and the three most recently opened projects right after OpenCode
  readiness, sequentially and best-effort, overlapping UI startup.

Validation: new background-network tests, lifecycle warmup test, focused
store/sync tests, UI type-check and lint, dead-code report, node --check
plus electron type-check/lint, and CDP first-open measurements on the
packaged app (message fetch socket queue 5.4s -> 0.03s).

* fix(ui): keep interactive git reads out of background queue

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-07-31 12:51:15 +03:00

176 lines
5.7 KiB
TypeScript

const STORAGE_KEY = "openchamber_session_load_perf"
const MAX_EVENTS = 1_000
const ALLOWED_OPERATIONS = new Set([
"bootstrap.directory",
"bootstrap.sessions.all",
"bootstrap.sessions.archived",
"bootstrap.sessions.roots",
"global-sessions.active",
"global-sessions.archived",
"session-messages.initial",
"session-messages.older",
"session-messages.page",
"session-messages.refresh",
"session-messages.visible",
"session-prefetch",
])
const ALLOWED_CALLERS = new Set([
"action-demand",
"current-directory",
"initial",
"initial-page",
"known-project",
"known-worktree",
"older",
"pagination",
"prefetch",
"project-expanded",
"refresh",
"selected-session",
"server-connected",
"worktree-expanded",
])
const ALLOWED_OUTCOMES = new Set<SessionLoadPerformanceOutcome>([
"complete",
"error",
"stale",
"deduplicated",
"canceled",
])
type SessionLoadPerformanceOutcome = "complete" | "error" | "stale" | "deduplicated" | "canceled"
type SessionLoadPerformanceEvent = {
operation: string
caller?: string
queuedMs?: number
requestLimit?: number
cursorPresent?: boolean
durationMs: number
outcome: SessionLoadPerformanceOutcome
retryCount?: number
recordCount?: number
at: number
}
type SessionLoadPerformanceState = {
events: SessionLoadPerformanceEvent[]
}
declare global {
interface Window {
__openchamberSessionLoadPerformance?: SessionLoadPerformanceState
}
}
const isSessionLoadPerformanceEnabled = (): boolean => {
if (typeof window === "undefined") return false
try {
return window.localStorage.getItem(STORAGE_KEY) === "1"
} catch {
return false
}
}
const now = (): number => typeof performance !== "undefined" && typeof performance.now === "function"
? performance.now()
: Date.now()
const nonNegativeNumber = (value: unknown): number | undefined => (
typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined
)
const nonNegativeInteger = (value: unknown): number | undefined => (
Number.isInteger(value) && Number(value) >= 0 ? Number(value) : undefined
)
export function startSessionLoadPerformanceEvent(input: Omit<SessionLoadPerformanceEvent, "at" | "durationMs" | "outcome">) {
if (
!isSessionLoadPerformanceEnabled()
|| !ALLOWED_OPERATIONS.has(input.operation)
|| (input.caller !== undefined && !ALLOWED_CALLERS.has(input.caller))
) return () => undefined
const startedAt = now()
return (
outcome: SessionLoadPerformanceOutcome,
details?: Partial<Pick<SessionLoadPerformanceEvent, "retryCount" | "recordCount">>,
) => {
if (typeof window === "undefined" || !ALLOWED_OUTCOMES.has(outcome)) return
const state = window.__openchamberSessionLoadPerformance ?? { events: [] }
const queuedMs = nonNegativeNumber(input.queuedMs)
const requestLimit = nonNegativeInteger(input.requestLimit)
const retryCount = nonNegativeInteger(details?.retryCount ?? input.retryCount)
const recordCount = nonNegativeInteger(details?.recordCount ?? input.recordCount)
state.events.push({
operation: input.operation,
...(input.caller !== undefined ? { caller: input.caller } : {}),
...(queuedMs !== undefined ? { queuedMs } : {}),
...(requestLimit !== undefined ? { requestLimit } : {}),
...(typeof input.cursorPresent === "boolean" ? { cursorPresent: input.cursorPresent } : {}),
outcome,
durationMs: Math.max(0, now() - startedAt),
...(retryCount !== undefined ? { retryCount } : {}),
...(recordCount !== undefined ? { recordCount } : {}),
at: Date.now(),
})
if (state.events.length > MAX_EVENTS) state.events.splice(0, state.events.length - MAX_EVENTS)
window.__openchamberSessionLoadPerformance = state
}
}
type FirstVisibleSessionPerformanceDependencies = {
enabled: () => boolean
requestFrame: (callback: FrameRequestCallback) => number
cancelFrame: (frame: number) => void
markVisible: () => void
startEvent: typeof startSessionLoadPerformanceEvent
}
const FIRST_VISIBLE_MARK = "openchamber.chat.first_message_visible"
export function createFirstVisibleSessionPerformanceTracker(
dependencies?: Partial<FirstVisibleSessionPerformanceDependencies>,
) {
const enabled = dependencies?.enabled ?? isSessionLoadPerformanceEnabled
const requestFrame = dependencies?.requestFrame ?? ((callback) => window.requestAnimationFrame(callback))
const cancelFrame = dependencies?.cancelFrame ?? ((frame) => window.cancelAnimationFrame(frame))
const markVisible = dependencies?.markVisible ?? (() => {
performance.mark(FIRST_VISIBLE_MARK)
performance.clearMarks(FIRST_VISIBLE_MARK)
})
const startEvent = dependencies?.startEvent ?? startSessionLoadPerformanceEvent
const measuredKeys = new Set<string>()
let pending: { key: string; frame: number } | null = null
return {
schedule(key: string, recordCount: number): () => void {
if (!enabled() || measuredKeys.has(key)) return () => undefined
if (pending) {
cancelFrame(pending.frame)
pending = null
}
const finishPerformanceEvent = startEvent({
operation: "session-messages.visible",
caller: "selected-session",
recordCount,
})
const frame = requestFrame(() => {
if (pending?.key !== key || pending.frame !== frame) return
pending = null
measuredKeys.add(key)
if (measuredKeys.size > MAX_EVENTS) {
measuredKeys.delete(measuredKeys.values().next().value!)
}
markVisible()
finishPerformanceEvent("complete")
})
pending = { key, frame }
return () => {
if (pending?.key !== key || pending.frame !== frame) return
cancelFrame(frame)
pending = null
}
},
}
}