All checks were successful
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s
Stream large receives to disk with chunk acks to cap renderer RAM, evict off-screen display blobs, and route exports through a disk-aware download service. Fix the high-memory dialog (backdrop dismiss, copy, log actions), allow diagnostics paths in the path jail, and restore persisted image hydration after reload. Co-authored-by: Cursor <cursoragent@cursor.com>
81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
import type { BrowserWindow } from 'electron';
|
|
import type { AppMetricsSnapshot } from '../app-metrics';
|
|
import { buildHighMemoryDiagnosticPayload } from './high-memory-snapshot.rules';
|
|
import { collectImmediateRendererSamples } from './immediate-renderer-samples.collector';
|
|
import { collectSessionContext } from './session-context.collector';
|
|
import type { HighMemoryAlertRecord } from './high-memory-alert.store';
|
|
import type { PerfDiagEntry } from './diagnostics.models';
|
|
import { PerfDiagWriter } from './diagnostics.writer';
|
|
|
|
export type HighMemoryCaptureReason = 'manual' | 'threshold';
|
|
|
|
export interface CaptureHighMemoryDiagnosticsInput {
|
|
userDataPath: string;
|
|
sessionStartedAt: number;
|
|
metrics: AppMetricsSnapshot;
|
|
totalWorkingSetKb: number;
|
|
writer: PerfDiagWriter | null;
|
|
mainWindow: BrowserWindow | null;
|
|
reason: HighMemoryCaptureReason;
|
|
}
|
|
|
|
export async function captureHighMemoryDiagnostics(
|
|
input: CaptureHighMemoryDiagnosticsInput
|
|
): Promise<HighMemoryAlertRecord> {
|
|
const detectedAt = Date.now();
|
|
const writer = input.writer ?? new PerfDiagWriter({
|
|
userDataPath: input.userDataPath,
|
|
sessionId: `${input.reason}-${detectedAt.toString(36)}-${process.pid}`
|
|
});
|
|
const immediateRendererEntries = await collectImmediateRendererSamples(input.mainWindow);
|
|
const environment = collectSessionContext({
|
|
sessionStartedAt: input.sessionStartedAt,
|
|
userDataPath: input.userDataPath
|
|
});
|
|
|
|
appendEntries(writer, immediateRendererEntries);
|
|
appendEntries(writer, [
|
|
{
|
|
collectedAt: detectedAt,
|
|
source: 'main',
|
|
type: 'environment',
|
|
payload: {
|
|
...environment
|
|
}
|
|
},
|
|
{
|
|
collectedAt: detectedAt,
|
|
source: 'main',
|
|
type: 'high-memory',
|
|
payload: buildHighMemoryDiagnosticPayload({
|
|
detectedAt,
|
|
totalWorkingSetKb: input.totalWorkingSetKb,
|
|
metrics: input.metrics,
|
|
environment,
|
|
mainProcessMemory: process.memoryUsage(),
|
|
ringEntries: writer.bufferedEntries,
|
|
immediateRendererEntries,
|
|
sessionId: writer.sessionId
|
|
})
|
|
}
|
|
]);
|
|
|
|
await writer.flushSnapshot(
|
|
input.reason === 'manual' ? 'manual-export' : 'high-memory-threshold'
|
|
);
|
|
|
|
return {
|
|
logFilePath: writer.snapshotFilePath,
|
|
detectedAt,
|
|
peakWorkingSetKb: input.totalWorkingSetKb,
|
|
sessionId: writer.sessionId,
|
|
reason: input.reason
|
|
};
|
|
}
|
|
|
|
function appendEntries(writer: PerfDiagWriter, entries: readonly PerfDiagEntry[]): void {
|
|
for (const entry of entries) {
|
|
writer.append(entry);
|
|
}
|
|
}
|