mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 11:48:42 +02:00
fix: resolve AI response not rendering after long idle/sleep (#129)
* fix: resolve AI response not rendering after long idle/sleep
- Add backgroundThrottling: false to prevent Chromium from throttling
the renderer process when the window is in the background
- Add powerMonitor.on('resume') to send APP_FOCUS event after system
wake, triggering DB sync to recover any missed IPC messages
- Re-sync session updates from DB on app focus to capture messages
lost during sleep/wake or background throttling
- Guard async DB sync with currentSessionIdRef check to prevent
race condition when user switches sessions during the async call
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: dedupe focus resync logs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import log from './logger'
|
||||
|
||||
log.info('Multica starting...')
|
||||
|
||||
import { app, shell, BrowserWindow, ipcMain } from 'electron'
|
||||
import { app, shell, BrowserWindow, ipcMain, powerMonitor } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||
import icon from '../../resources/icon.png?asset'
|
||||
@@ -42,7 +42,8 @@ function createWindow(): BrowserWindow {
|
||||
preload: join(__dirname, '../preload/index.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
sandbox: true
|
||||
sandbox: true,
|
||||
backgroundThrottling: false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -150,6 +151,13 @@ app.whenReady().then(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
// Notify renderer when system resumes from sleep (reuse APP_FOCUS to trigger DB sync)
|
||||
powerMonitor.on('resume', () => {
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send(IPC_CHANNELS.APP_FOCUS)
|
||||
}
|
||||
})
|
||||
|
||||
// Initialize auto-updater
|
||||
// Set FORCE_DEV_UPDATE=true to test updates in dev mode
|
||||
const forceDevUpdate = process.env.FORCE_DEV_UPDATE === 'true'
|
||||
|
||||
@@ -14,6 +14,7 @@ import { useFileChangeStore } from '../stores/fileChangeStore'
|
||||
import { useCommandStore } from '../stores/commandStore'
|
||||
import { useAgentStore } from '../stores/agentStore'
|
||||
import { toast } from 'sonner'
|
||||
import { mergeSessionUpdates } from '../utils/sessionUpdates'
|
||||
|
||||
function isGitHeadPath(filePath: string): boolean {
|
||||
const normalizedPath = filePath.replace(/\\/g, '/')
|
||||
@@ -59,6 +60,8 @@ export function useAppSubscriptions(callbacks: SubscriptionCallbacks): void {
|
||||
|
||||
// Debounce timer for git branch refresh
|
||||
const gitBranchRefreshTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const focusSyncInFlightRef = useRef(false)
|
||||
const lastFocusSyncAtRef = useRef(0)
|
||||
|
||||
// Get current session ID for stable reference in effects
|
||||
const currentSessionId = currentSession?.id
|
||||
@@ -232,6 +235,38 @@ export function useAppSubscriptions(callbacks: SubscriptionCallbacks): void {
|
||||
|
||||
if (currentSession) {
|
||||
await Promise.all([agentRefresh, callbacks.validateCurrentSessionDirectory()])
|
||||
|
||||
// Re-sync session updates from DB to capture any IPC messages that were
|
||||
// lost during system sleep/wake or Chromium background throttling
|
||||
try {
|
||||
const now = Date.now()
|
||||
if (focusSyncInFlightRef.current || now - lastFocusSyncAtRef.current < 500) {
|
||||
if (import.meta.env.DEV) {
|
||||
console.log(
|
||||
'[useAppSubscriptions] Skip focus sync (deduped)',
|
||||
'inFlight:',
|
||||
focusSyncInFlightRef.current,
|
||||
'ageMs:',
|
||||
now - lastFocusSyncAtRef.current
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
focusSyncInFlightRef.current = true
|
||||
lastFocusSyncAtRef.current = now
|
||||
const sessionId = currentSession.id
|
||||
if (import.meta.env.DEV) {
|
||||
console.log('[useAppSubscriptions] Focus sync start', sessionId)
|
||||
}
|
||||
const freshData = await window.electronAPI.getSession(sessionId)
|
||||
if (freshData?.updates && currentSessionIdRef.current === sessionId) {
|
||||
setSessionUpdates((prev) => mergeSessionUpdates(prev, freshData.updates))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[useAppSubscriptions] Failed to refresh session updates on focus:', err)
|
||||
} finally {
|
||||
focusSyncInFlightRef.current = false
|
||||
}
|
||||
} else {
|
||||
await agentRefresh
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user