fix(app-state): refactor quitting logic to use setQuitting function (#199)

This commit is contained in:
Haze
2026-02-26 22:57:03 +08:00
committed by GitHub
Unverified
parent 45d5e9e576
commit 3420ee2447
3 changed files with 16 additions and 14 deletions

View File

@@ -0,0 +1,5 @@
export let isQuitting = false;
export function setQuitting(value = true): void {
isQuitting = value;
}

View File

@@ -15,13 +15,13 @@ import { warmupNetworkOptimization } from '../utils/uv-env';
import { ClawHubService } from '../gateway/clawhub'; import { ClawHubService } from '../gateway/clawhub';
import { ensureClawXContext, repairClawXOnlyBootstrapFiles } from '../utils/openclaw-workspace'; import { ensureClawXContext, repairClawXOnlyBootstrapFiles } from '../utils/openclaw-workspace';
import { isQuitting, setQuitting } from './app-state';
// Disable GPU acceleration for better compatibility // Disable GPU acceleration for better compatibility
app.disableHardwareAcceleration(); app.disableHardwareAcceleration();
// Global references // Global references
let mainWindow: BrowserWindow | null = null; let mainWindow: BrowserWindow | null = null;
let isQuitting = false;
const gatewayManager = new GatewayManager(); const gatewayManager = new GatewayManager();
const clawHubService = new ClawHubService(); const clawHubService = new ClawHubService();
@@ -239,7 +239,7 @@ app.on('window-all-closed', () => {
}); });
app.on('before-quit', () => { app.on('before-quit', () => {
isQuitting = true; setQuitting();
// Fire-and-forget: do not await gatewayManager.stop() here. // Fire-and-forget: do not await gatewayManager.stop() here.
// Awaiting inside before-quit can stall Electron's quit sequence. // Awaiting inside before-quit can stall Electron's quit sequence.
void gatewayManager.stop().catch((err) => { void gatewayManager.stop().catch((err) => {

View File

@@ -10,6 +10,7 @@ import { autoUpdater, UpdateInfo, ProgressInfo, UpdateDownloadedEvent } from 'el
import { BrowserWindow, app, ipcMain } from 'electron'; import { BrowserWindow, app, ipcMain } from 'electron';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { setQuitting } from './app-state';
/** Base CDN URL (without trailing channel path) */ /** Base CDN URL (without trailing channel path) */
const OSS_BASE_URL = 'https://oss.intelli-spectrum.com'; const OSS_BASE_URL = 'https://oss.intelli-spectrum.com';
@@ -209,22 +210,18 @@ export class AppUpdater extends EventEmitter {
/** /**
* Install update and restart. * Install update and restart.
* *
* On macOS, electron-updater's MacUpdater still delegates to Squirrel.Mac * On macOS, electron-updater delegates to Squirrel.Mac (ShipIt). The
* internally. Squirrel's quitAndInstall() is unreliable — it sometimes * native quitAndInstall() spawns ShipIt then internally calls app.quit().
* fails to trigger `before-quit`, leaving the tray close handler to * However, the tray close handler in index.ts intercepts window close
* intercept and hide the window instead of quitting. We force `app.quit()` * and hides to tray unless isQuitting is true. Squirrel's internal quit
* after a short grace period as a safety net. * sometimes fails to trigger before-quit in time, so we set isQuitting
* BEFORE calling quitAndInstall(). This lets the native quit flow close
* the window cleanly while ShipIt runs independently to replace the app.
*/ */
quitAndInstall(): void { quitAndInstall(): void {
logger.info('[Updater] quitAndInstall called'); logger.info('[Updater] quitAndInstall called');
setQuitting();
autoUpdater.quitAndInstall(); autoUpdater.quitAndInstall();
if (process.platform === 'darwin') {
setTimeout(() => {
logger.warn('[Updater] macOS: forcing app.quit() (Squirrel fallback)');
app.quit();
}, 3_000).unref();
}
} }
/** /**