mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
fix(crash-reporting): scope auto-recovery resolution to renderer process crashes
React error-boundary reports share source 'renderer' but are produced by the renderer itself, not by a dead process, so a recovery reload must not dismiss them. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -136,7 +136,14 @@ export class CrashReportStore {
|
||||
return this.withWrite(async (reports) => {
|
||||
const resolved: CrashReportRecord[] = []
|
||||
const nextReports = reports.map((report) => {
|
||||
if (report.status !== 'pending' || report.source !== 'renderer') {
|
||||
// Why: `source: 'renderer'` also covers React error-boundary reports
|
||||
// (processType 'react-render'), which the recovery reload did not cause
|
||||
// and must keep prompting on their own evidence.
|
||||
if (
|
||||
report.status !== 'pending' ||
|
||||
report.source !== 'renderer' ||
|
||||
report.processType !== 'renderer'
|
||||
) {
|
||||
return report
|
||||
}
|
||||
const createdAtMs = Date.parse(report.createdAt)
|
||||
|
||||
@@ -90,6 +90,18 @@ function killedRendererCrash(exitCode = 9): CrashReportCreateInput {
|
||||
}
|
||||
}
|
||||
|
||||
// Same `source`, different producer: reported by the renderer's own error
|
||||
// boundary, not by a dead renderer process.
|
||||
function reactErrorBoundaryCrash(): CrashReportCreateInput {
|
||||
return {
|
||||
...killedRendererCrash(),
|
||||
processType: 'react-render',
|
||||
reason: 'react-error-boundary',
|
||||
exitCode: null,
|
||||
details: { processType: 'react-render' }
|
||||
}
|
||||
}
|
||||
|
||||
function emitRendererBootstrapRendered(): void {
|
||||
listeners.get('crashReports:recordBreadcrumb')?.(null, { name: 'renderer_bootstrap_rendered' })
|
||||
}
|
||||
@@ -156,6 +168,30 @@ describe('auto-recovered renderer crash reporting', () => {
|
||||
expect(sendable?.breadcrumbs).toEqual(recorded.breadcrumbs)
|
||||
})
|
||||
|
||||
it('still prompts for a React error-boundary crash caught in the recovery window', async () => {
|
||||
const store = await createStore()
|
||||
registerCrashReportingHandlers(store)
|
||||
const recorded = await store.record(reactErrorBoundaryCrash())
|
||||
|
||||
noteRendererRecoveryReloadIssued()
|
||||
emitRendererBootstrapRendered()
|
||||
|
||||
await expect(getLatestPending()).resolves.toMatchObject({ id: recorded.id, status: 'pending' })
|
||||
expect((await getLatestReport())?.details.rendererAutoRecovered).toBeUndefined()
|
||||
})
|
||||
|
||||
it('resolves the process crash without sweeping a React error-boundary crash beside it', async () => {
|
||||
const store = await createStore()
|
||||
registerCrashReportingHandlers(store)
|
||||
const boundary = await store.record(reactErrorBoundaryCrash())
|
||||
await store.record(killedRendererCrash())
|
||||
|
||||
noteRendererRecoveryReloadIssued()
|
||||
emitRendererBootstrapRendered()
|
||||
|
||||
await expect(getLatestPending()).resolves.toMatchObject({ id: boundary.id, status: 'pending' })
|
||||
})
|
||||
|
||||
it('still prompts when the renderer booted without an auto-recovery reload', async () => {
|
||||
const store = await createStore()
|
||||
registerCrashReportingHandlers(store)
|
||||
|
||||
Reference in New Issue
Block a user