mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
perf(startup): read the HTTP/1.1 compatibility flag from a marker, not the settings file
configureElectronNetworkCompatibility() runs before app.whenReady(), and it answered one boolean by synchronously reading and JSON.parsing the whole orca-data.json — 1.54 MB on a real profile here, measured at 6.6ms read + 3.5ms parse. The Store parses the identical file again moments later, so the first parse was pure waste on the critical path of every cold start. Cache the flag in a few-byte marker next to the other pre-ready markers (gpu-fallback, hang-detection), written at store load and whenever the setting changes. When no marker exists yet the old full read still runs, so an upgrading profile keeps the setting on its first launch.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { homedir, tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -444,6 +444,43 @@ describe('configureElectronNetworkCompatibility', () => {
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it('answers from the marker without reading the settings file', async () => {
|
||||
const { shouldDisableHttp2ForElectronNetworking } = await import('./configure-process')
|
||||
const { writeHttp1CompatibilityMarker } = await import('./http1-compatibility-marker')
|
||||
const userDataPath = createUserDataDir({ electronHttp1CompatibilityMode: false })
|
||||
writeHttp1CompatibilityMarker(userDataPath, true)
|
||||
rmSync(join(userDataPath, 'orca-data.json'), { force: true })
|
||||
|
||||
expect(shouldDisableHttp2ForElectronNetworking({ env: {}, userDataPath })).toBe(true)
|
||||
})
|
||||
|
||||
it('falls back to the settings file when no marker has been written yet', async () => {
|
||||
const { shouldDisableHttp2ForElectronNetworking } = await import('./configure-process')
|
||||
const userDataPath = createUserDataDir({ electronHttp1CompatibilityMode: true })
|
||||
|
||||
expect(existsSync(join(userDataPath, 'http1-compatibility.json'))).toBe(false)
|
||||
expect(shouldDisableHttp2ForElectronNetworking({ env: {}, userDataPath })).toBe(true)
|
||||
})
|
||||
|
||||
it('falls back to the settings file when the marker is corrupt', async () => {
|
||||
const { shouldDisableHttp2ForElectronNetworking } = await import('./configure-process')
|
||||
const userDataPath = createUserDataDir({ electronHttp1CompatibilityMode: true })
|
||||
writeFileSync(join(userDataPath, 'http1-compatibility.json'), '{ not json', 'utf-8')
|
||||
|
||||
expect(shouldDisableHttp2ForElectronNetworking({ env: {}, userDataPath })).toBe(true)
|
||||
})
|
||||
|
||||
it('lets the environment override the marker', async () => {
|
||||
const { shouldDisableHttp2ForElectronNetworking } = await import('./configure-process')
|
||||
const { writeHttp1CompatibilityMarker } = await import('./http1-compatibility-marker')
|
||||
const userDataPath = createUserDataDir({})
|
||||
writeHttp1CompatibilityMarker(userDataPath, true)
|
||||
|
||||
expect(
|
||||
shouldDisableHttp2ForElectronNetworking({ env: { ORCA_DISABLE_HTTP2: '0' }, userDataPath })
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it('appends Electron disable-http2 before sessions are created', async () => {
|
||||
const { app } = await import('electron')
|
||||
const { configureElectronNetworkCompatibility } = await import('./configure-process')
|
||||
|
||||
@@ -5,6 +5,7 @@ import { join, resolve } from 'node:path'
|
||||
import { getVersionManagerBinPaths } from '../codex-cli/command'
|
||||
import { getMainE2EConfig } from '../e2e-config'
|
||||
import { DISABLED_CHROMIUM_FEATURES } from './disabled-chromium-features'
|
||||
import { readHttp1CompatibilityMarker } from './http1-compatibility-marker'
|
||||
|
||||
const DEV_PARENT_SHUTDOWN_GRACE_MS = 3000
|
||||
const HTTP1_COMPATIBILITY_ENV_VAR = 'ORCA_DISABLE_HTTP2'
|
||||
@@ -54,7 +55,13 @@ export function shouldDisableHttp2ForElectronNetworking(
|
||||
if (envValue !== null) {
|
||||
return envValue
|
||||
}
|
||||
return readPersistedHttp1CompatibilityMode(options.userDataPath ?? app.getPath('userData'))
|
||||
const userDataPath = options.userDataPath ?? app.getPath('userData')
|
||||
// Why the marker first: this runs before app.whenReady(), and the settings file is the multi-MB
|
||||
// orca-data.json the Store parses again moments later. The marker is refreshed whenever settings
|
||||
// change, so the full read only happens on a profile that has never written one.
|
||||
return (
|
||||
readHttp1CompatibilityMarker(userDataPath) ?? readPersistedHttp1CompatibilityMode(userDataPath)
|
||||
)
|
||||
}
|
||||
|
||||
export function configureElectronNetworkCompatibility(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
/**
|
||||
* Cached copy of `settings.electronHttp1CompatibilityMode` for pre-`ready` startup.
|
||||
*
|
||||
* Why a standalone file (not the Store): app.commandLine.appendSwitch('disable-http2') must run
|
||||
* before the first Electron session exists, which is before the settings Store is constructed.
|
||||
* Reading it from the settings file meant a synchronous read + JSON.parse of the whole multi-MB
|
||||
* orca-data.json on the critical path of every cold start, duplicating the parse the Store does a
|
||||
* moment later. This marker is a few bytes, mirroring gpu-fallback-marker.ts.
|
||||
*/
|
||||
|
||||
export const HTTP1_COMPATIBILITY_MARKER_FILE = 'http1-compatibility.json'
|
||||
const MARKER_SCHEME_VERSION = 1
|
||||
|
||||
type Http1CompatibilityMarker = {
|
||||
schemeVersion: number
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
function markerPath(userDataPath: string): string {
|
||||
return join(userDataPath, HTTP1_COMPATIBILITY_MARKER_FILE)
|
||||
}
|
||||
|
||||
/** Returns null when the marker is missing or unreadable, so callers fall back to the settings file. */
|
||||
export function readHttp1CompatibilityMarker(userDataPath: string): boolean | null {
|
||||
try {
|
||||
const parsed = JSON.parse(
|
||||
readFileSync(markerPath(userDataPath), 'utf-8')
|
||||
) as Partial<Http1CompatibilityMarker>
|
||||
if (parsed.schemeVersion !== MARKER_SCHEME_VERSION || typeof parsed.enabled !== 'boolean') {
|
||||
return null
|
||||
}
|
||||
return parsed.enabled
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function writeHttp1CompatibilityMarker(userDataPath: string, enabled: boolean): void {
|
||||
if (readHttp1CompatibilityMarker(userDataPath) === enabled) {
|
||||
return
|
||||
}
|
||||
const marker: Http1CompatibilityMarker = { schemeVersion: MARKER_SCHEME_VERSION, enabled }
|
||||
try {
|
||||
writeFileSync(markerPath(userDataPath), JSON.stringify(marker))
|
||||
} catch {
|
||||
// Best effort: a missing marker just costs the next launch the settings-file fallback.
|
||||
}
|
||||
}
|
||||
|
||||
export function clearHttp1CompatibilityMarker(userDataPath: string): void {
|
||||
try {
|
||||
rmSync(markerPath(userDataPath), { force: true })
|
||||
} catch {
|
||||
// Best effort; a stale marker is revalidated on the next settings change.
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import { registerDocPreviewGrantHandlers } from '../ipc/doc-preview-grant-ipc'
|
||||
import { initializeBrowserSessionsForApp } from '../browser/browser-session-startup'
|
||||
import { browserSessionRegistry } from '../browser/browser-session-registry'
|
||||
import { logStartupMilestone } from './startup-diagnostics'
|
||||
import { writeHttp1CompatibilityMarker } from './http1-compatibility-marker'
|
||||
import { mainProcessState as state } from './main-process-state'
|
||||
import { recordDurableCrashBreadcrumb } from '../crash-reporting/durable-crash-breadcrumb'
|
||||
import { syncMacMenuBarIcon } from './main-window-actions'
|
||||
@@ -193,9 +194,20 @@ export async function initializeReadyFoundation(): Promise<void> {
|
||||
}
|
||||
wslHookRelayManager.setManagedHookSettingsResolver(() => state.store?.getSettings() ?? null)
|
||||
logStartupMilestone('store-loaded')
|
||||
// Why: pre-`ready` startup reads this flag from a marker so it never has to parse orca-data.json.
|
||||
writeHttp1CompatibilityMarker(
|
||||
canonicalUserDataPath,
|
||||
store.getSettings().electronHttp1CompatibilityMode === true
|
||||
)
|
||||
// Why: apply initial fallback WSL distro from store settings for global git/CLI calls.
|
||||
setDefaultWslDistroOverride(store.getSettings().terminalWindowsWslDistro ?? null)
|
||||
store.onSettingsChanged((updates, settings) => {
|
||||
if ('electronHttp1CompatibilityMode' in updates) {
|
||||
writeHttp1CompatibilityMarker(
|
||||
canonicalUserDataPath,
|
||||
settings.electronHttp1CompatibilityMode === true
|
||||
)
|
||||
}
|
||||
if ('terminalWindowsWslDistro' in updates) {
|
||||
// Why: synchronize fallback WSL distro updates to runner.
|
||||
setDefaultWslDistroOverride(settings.terminalWindowsWslDistro ?? null)
|
||||
|
||||
Reference in New Issue
Block a user