mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* perf(main): take the idle ownership poll off the main thread and batch pending marker probes The runtime-metadata ownership watch ran existsSync + readFileSync + JSON.parse on the main thread every 10s for the life of the process. Move it to fs/promises with an ENOENT catch (dropping the existsSync pre-check, a TOCTOU race anyway) and guard overlapping ticks. The base-directory poller's pending `.git` marker probes ran serially, costing D x latency per tick for up to 300 ticks. Route them through the same forEachWithConcurrency bound the full scan already uses. * test(runtime): pin that a shutdown-straddling ownership read cannot republish CodeRabbit flagged the async read resuming after stop(). The cleared activeTransports guard already neutralizes it; this test pins that guard rather than the interval teardown.
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import { existsSync, readFileSync, rmSync } from 'node:fs'
|
|
import { readFile } from 'node:fs/promises'
|
|
import { getRuntimeMetadataPath, type RuntimeMetadata } from '../../shared/runtime-bootstrap'
|
|
import { writeSecureJsonFile } from '../../shared/secure-file'
|
|
|
|
export function writeRuntimeMetadata(userDataPath: string, metadata: RuntimeMetadata): void {
|
|
const metadataPath = getRuntimeMetadataPath(userDataPath)
|
|
writeMetadataFile(metadataPath, metadata)
|
|
}
|
|
|
|
export function readRuntimeMetadata(userDataPath: string): RuntimeMetadata | null {
|
|
const metadataPath = getRuntimeMetadataPath(userDataPath)
|
|
if (!existsSync(metadataPath)) {
|
|
return null
|
|
}
|
|
return JSON.parse(readFileSync(metadataPath, 'utf-8')) as RuntimeMetadata
|
|
}
|
|
|
|
/** Off-thread twin of {@link readRuntimeMetadata} for pollers; a missing file is not an error. */
|
|
export async function readRuntimeMetadataAsync(
|
|
userDataPath: string
|
|
): Promise<RuntimeMetadata | null> {
|
|
let raw: string
|
|
try {
|
|
raw = await readFile(getRuntimeMetadataPath(userDataPath), 'utf-8')
|
|
} catch (error) {
|
|
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
return null
|
|
}
|
|
throw error
|
|
}
|
|
return JSON.parse(raw) as RuntimeMetadata
|
|
}
|
|
|
|
export function clearRuntimeMetadata(userDataPath: string): void {
|
|
rmSync(getRuntimeMetadataPath(userDataPath), { force: true })
|
|
}
|
|
|
|
/**
|
|
* Why: clearing metadata unconditionally on quit would race with a sibling
|
|
* Orca process during auto-updater handoff (the new process may already
|
|
* have written its own metadata before the old process finishes tearing
|
|
* down). The ownership guard — pid + runtimeId must both match the values
|
|
* the caller recorded at its own startup — keeps the clean-exit case honest
|
|
* ('not_running' instead of 'stale_bootstrap') while refusing to erase the
|
|
* replacement process's fresh bootstrap.
|
|
*
|
|
* Callers MUST capture `ownedPid` and `ownedRuntimeId` synchronously at
|
|
* startup (or at least before any shutdown await) so the comparison below
|
|
* reflects the process that actually wrote the file, not whatever state
|
|
* globals happen to hold mid-teardown.
|
|
*/
|
|
export function clearRuntimeMetadataIfOwned(
|
|
userDataPath: string,
|
|
ownedPid: number,
|
|
ownedRuntimeId: string
|
|
): void {
|
|
const current = readRuntimeMetadata(userDataPath)
|
|
if (!current) {
|
|
return
|
|
}
|
|
if (current.pid !== ownedPid) {
|
|
return
|
|
}
|
|
if (current.runtimeId !== ownedRuntimeId) {
|
|
return
|
|
}
|
|
clearRuntimeMetadata(userDataPath)
|
|
}
|
|
|
|
function writeMetadataFile(path: string, metadata: RuntimeMetadata): void {
|
|
writeSecureJsonFile(path, metadata)
|
|
}
|