From 8689465e0028971a9a5f1c6abc5d8ff5b9550325 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Wed, 20 Nov 2024 14:44:06 +0800 Subject: [PATCH] fix(electron): potential crash on quit (#8855) --- .github/workflows/release-desktop.yml | 2 ++ .../apps/electron/src/main/cleanup.ts | 20 +++++++++++++++++++ .../frontend/apps/electron/src/main/events.ts | 15 ++++++-------- .../apps/electron/src/main/helper-process.ts | 3 ++- .../src/main/windows-manager/main-window.ts | 7 +++++++ .../src/main/windows-manager/tab-views.ts | 7 +++++-- 6 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 packages/frontend/apps/electron/src/main/cleanup.ts diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index f6897a7a26..ded78ad0d1 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -97,6 +97,7 @@ jobs: SENTRY_PROJECT: 'affine' SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_RELEASE: ${{ needs.before-make.outputs.RELEASE_VERSION }} MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_TOKEN }} steps: - uses: actions/checkout@v4 @@ -213,6 +214,7 @@ jobs: SENTRY_PROJECT: 'affine' SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_RELEASE: ${{ needs.before-make.outputs.RELEASE_VERSION }} MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_TOKEN }} steps: - uses: actions/checkout@v4 diff --git a/packages/frontend/apps/electron/src/main/cleanup.ts b/packages/frontend/apps/electron/src/main/cleanup.ts new file mode 100644 index 0000000000..1fd5c343b2 --- /dev/null +++ b/packages/frontend/apps/electron/src/main/cleanup.ts @@ -0,0 +1,20 @@ +import { app } from 'electron'; + +import { logger } from './logger'; + +const cleanupRegistry: (() => void)[] = []; + +export function beforeAppQuit(fn: () => void) { + cleanupRegistry.push(fn); +} + +app.on('before-quit', () => { + cleanupRegistry.forEach(fn => { + // some cleanup functions might throw on quit and crash the app + try { + fn(); + } catch (err) { + logger.warn('cleanup error on quit', err); + } + }); +}); diff --git a/packages/frontend/apps/electron/src/main/events.ts b/packages/frontend/apps/electron/src/main/events.ts index fcb5547ad5..51b5c1b07e 100644 --- a/packages/frontend/apps/electron/src/main/events.ts +++ b/packages/frontend/apps/electron/src/main/events.ts @@ -1,7 +1,8 @@ -import { app, BrowserWindow, WebContentsView } from 'electron'; +import { BrowserWindow, WebContentsView } from 'electron'; import { AFFINE_EVENT_CHANNEL_NAME } from '../shared/type'; import { applicationMenuEvents } from './application-menu'; +import { beforeAppQuit } from './cleanup'; import { logger } from './logger'; import { sharedStorageEvents } from './shared-storage'; import { uiEvents } from './ui/events'; @@ -56,14 +57,10 @@ export function registerEvents() { unsubs.push(unsubscribe); } } - app.on('before-quit', () => { - // subscription on quit sometimes crashes the app - unsubs.forEach(unsub => { - try { - unsub(); - } catch (err) { - logger.warn('unsubscribe error on quit', err); - } + + unsubs.forEach(unsub => { + beforeAppQuit(() => { + unsub(); }); }); } diff --git a/packages/frontend/apps/electron/src/main/helper-process.ts b/packages/frontend/apps/electron/src/main/helper-process.ts index f2b4e5a615..d068d49d4e 100644 --- a/packages/frontend/apps/electron/src/main/helper-process.ts +++ b/packages/frontend/apps/electron/src/main/helper-process.ts @@ -13,6 +13,7 @@ import { import type { HelperToMain, MainToHelper } from '../shared/type'; import { MessageEventChannel } from '../shared/utils'; +import { beforeAppQuit } from './cleanup'; import { logger } from './logger'; const HELPER_PROCESS_PATH = path.join(__dirname, './helper.js'); @@ -65,7 +66,7 @@ class HelperProcessManager { }); }); - app.on('before-quit', () => { + beforeAppQuit(() => { this.#process.kill(); }); } diff --git a/packages/frontend/apps/electron/src/main/windows-manager/main-window.ts b/packages/frontend/apps/electron/src/main/windows-manager/main-window.ts index 09fbf91848..6dcf8a04df 100644 --- a/packages/frontend/apps/electron/src/main/windows-manager/main-window.ts +++ b/packages/frontend/apps/electron/src/main/windows-manager/main-window.ts @@ -5,6 +5,7 @@ import electronWindowState from 'electron-window-state'; import { BehaviorSubject } from 'rxjs'; import { isLinux, isMacOS, isWindows } from '../../shared/utils'; +import { beforeAppQuit } from '../cleanup'; import { buildType } from '../config'; import { mainWindowOrigin } from '../constants'; import { ensureHelperProcess } from '../helper-process'; @@ -116,11 +117,17 @@ export class MainWindowManager { uiSubjects.onFullScreen$.next(mainWindow.isFullScreen()); }); + beforeAppQuit(() => { + this.cleanupWindows(); + }); + mainWindow.on('close', e => { // TODO(@pengx17): gracefully close the app, for example, ask user to save unsaved changes e.preventDefault(); if (!isMacOS()) { closeAllWindows(); + this.mainWindowReady = undefined; + this.mainWindow$.next(undefined); } else { // hide window on macOS // application quit will be handled by closing the hidden window diff --git a/packages/frontend/apps/electron/src/main/windows-manager/tab-views.ts b/packages/frontend/apps/electron/src/main/windows-manager/tab-views.ts index 87f64dc1f1..a224f8fbbd 100644 --- a/packages/frontend/apps/electron/src/main/windows-manager/tab-views.ts +++ b/packages/frontend/apps/electron/src/main/windows-manager/tab-views.ts @@ -25,6 +25,7 @@ import { } from 'rxjs'; import { isMacOS } from '../../shared/utils'; +import { beforeAppQuit } from '../cleanup'; import { CLOUD_BASE_URL, isDev } from '../config'; import { mainWindowOrigin, shellViewUrl } from '../constants'; import { ensureHelperProcess } from '../helper-process'; @@ -749,8 +750,10 @@ export class WebContentViewsManager { }) ); - app.on('before-quit', () => { - disposables.forEach(d => d.unsubscribe()); + disposables.forEach(d => { + beforeAppQuit(() => { + d.unsubscribe(); + }); }); const focusActiveView = () => {