Skip to content

Commit

Permalink
Fix main process sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish committed Jan 26, 2025
1 parent b03bd67 commit 039e2ca
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 39 deletions.
31 changes: 13 additions & 18 deletions src/main/integrations/sentry-minidump/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Scope,
ScopeData,
SentryError,
Session,
} from '@sentry/core';
import { NodeClient } from '@sentry/node';
import { app, crashReporter } from 'electron';
Expand All @@ -16,7 +17,7 @@ import { getEventDefaults } from '../../context';
import { EXIT_REASONS, getSentryCachePath, usesCrashpad } from '../../electron-normalize';
import { getRendererProperties, trackRendererProperties } from '../../renderers';
import { ElectronMainOptions } from '../../sdk';
import { checkPreviousSession } from '../../sessions';
import { previousSessionWasAbnormal, restorePreviousSession, setPreviousSessionAsCurrent } from '../../sessions';
import { BufferedWriteStore } from '../../store';
import { getMinidumpLoader, MinidumpLoader } from './minidump-loader';

Expand Down Expand Up @@ -212,23 +213,13 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
}
});

// For minidumps found at startup, we don't want @sentry/core to automatically crash the session. Instead we set
// the level to 'error' and change it back in this callback.
client.on('beforeSendEvent', (event) => {
if (event.platform === 'native') {
event.level = 'fatal';
}

return event;
});
let sessionToRestore: Session | undefined;

// Start to submit recent minidump crashes. This will load breadcrumbs and
// context information that was cached on disk in the previous app run, prior to the crash.
sendNativeCrashes(client, async (minidumpProcess) => {
const event: Event = {
// This should be set to 'fatal' but then the current session will be marked as crashed whereas we want to
// mark the previous session as crashed. The `beforeSendEvent` callback will change this back to 'fatal'.
level: 'error',
level: 'fatal',
platform: 'native',
tags: {
'event.environment': 'native',
Expand All @@ -248,13 +239,17 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
event.contexts = previousRun.event?.contexts;
}

sessionToRestore = await setPreviousSessionAsCurrent();

return event;
})
.then((minidumpsFound) =>
// Check for previous uncompleted session. If a previous session exists
// and no minidumps were found, its likely an abnormal exit
checkPreviousSession(minidumpsFound),
)
.then(async (minidumpsFound) => {
if (!minidumpsFound) {
await previousSessionWasAbnormal();
} else if (sessionToRestore) {
restorePreviousSession(sessionToRestore);
}
})
.catch((error) => logger.error(error));
},
};
Expand Down
67 changes: 64 additions & 3 deletions src/main/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,20 @@ let previousSession: Promise<Partial<Session> | undefined> | undefined;
function getSessionStore(): Store<SessionContext | undefined> {
if (!sessionStore) {
sessionStore = new Store<SessionContext | undefined>(getSentryCachePath(), 'session', undefined);
previousSession = sessionStore.get();
previousSession = sessionStore.get().then(sesh => sesh ? makeSession(sesh) : sesh);
}

return sessionStore;
}

/** Copies a session and removes the toJSON function so it can be serialised without conversion */
function makeSessionSafeToSerialize(session: Session): Session {
const copy = { ...session };
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
delete (copy as any).toJSON;
return copy;
}

let persistTimer: ReturnType<typeof setInterval> | undefined;

/** Starts a session */
Expand All @@ -45,7 +53,7 @@ export function startSession(sendOnCreate: boolean): void {
}

getSessionStore()
.set(session)
.set(makeSessionSafeToSerialize(session))
.catch(() => {
// Does not throw
});
Expand All @@ -55,7 +63,7 @@ export function startSession(sendOnCreate: boolean): void {
const currentSession = getCurrentScope().getSession();
// Only bother saving if it hasn't already ended
if (currentSession && currentSession.status === 'ok') {
await getSessionStore().set(currentSession);
await getSessionStore().set(makeSessionSafeToSerialize(currentSession));
}
}, PERSIST_INTERVAL_MS);
}
Expand Down Expand Up @@ -110,6 +118,59 @@ export async function unreportedDuringLastSession(crashDate: Date | undefined):
return crashTime > lastPersist && crashTime < prevSessionEnd;
}

/** Sets the previous session as the current session and returns any existing session */
export async function setPreviousSessionAsCurrent(): Promise<Session | undefined> {
const previous = await previousSession;

const scope = getCurrentScope();
const currentSession = scope.getSession();

if (previous) {
previousSession = undefined;

if (previous.status === 'ok') {
scope.setSession(makeSession(previous));
}
}

return currentSession;
}

/** Restores a session */
export function restorePreviousSession(session: Session): void {
getCurrentScope().setSession(session);
}

/** Report the previous session as abnormal */
export async function previousSessionWasAbnormal(): Promise<void> {
const client = getClient<NodeClient>();

const previous = await previousSession;

if (previous && client) {
// Ignore if the previous session is already ended
if (previous.status !== 'ok') {
previousSession = undefined;
return;
}

logger.log(`Found previous abnormal session`);

const sesh = makeSession(previous);

updateSession(sesh, {
status: 'abnormal',
errors: (sesh.errors || 0) + 1,
release: (previous as unknown as SerializedSession).attrs?.release,
environment: (previous as unknown as SerializedSession).attrs?.environment,
});

await client.sendSession(sesh);

previousSession = undefined;
}
}

/** Checks if the previous session needs sending as crashed or abnormal */
export async function checkPreviousSession(crashed: boolean): Promise<void> {
const client = getClient<NodeClient>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"init": false,
"started": 0,
"timestamp": 0,
"status": "ok",
"status": "exited",
"errors": 0,
"duration": 0,
"attrs": {
Expand Down
17 changes: 0 additions & 17 deletions test/e2e/test-apps/sessions/native-crash-main/session-4.json

This file was deleted.

0 comments on commit 039e2ca

Please sign in to comment.