fix(desktop): prevent backend zombie process and IPC listener leaks

This commit is contained in:
zhayujie
2026-06-22 15:46:49 +08:00
parent 49452e035d
commit c432681b2b
6 changed files with 34 additions and 15 deletions

View File

@@ -34,7 +34,7 @@ const App: React.FC = () => {
// Handle app-menu / shortcut actions forwarded from the main process.
useEffect(() => {
window.electronAPI?.onMenuAction?.((action) => {
const off = window.electronAPI?.onMenuAction?.((action) => {
if (action === 'new-chat') {
useSessionStore.getState().newSession()
navigate('/')
@@ -42,6 +42,7 @@ const App: React.FC = () => {
navigate('/settings')
}
})
return off
}, [navigate])
const handleLangChange = useCallback(() => forceUpdate((n) => n + 1), [])

View File

@@ -26,6 +26,7 @@ export function useBackend() {
useEffect(() => {
let cancelled = false
let offStatus: (() => void) | undefined
const api = window.electronAPI
const startPolling = async (port: number) => {
@@ -62,7 +63,7 @@ export function useBackend() {
startPolling(p)
})
api.onBackendStatus((data) => {
offStatus = api.onBackendStatus((data) => {
if (data.status === 'ready' && data.port) {
setState({ status: 'ready', port: data.port })
if (pollingRef.current) {
@@ -82,6 +83,7 @@ export function useBackend() {
if (pollingRef.current) {
clearTimeout(pollingRef.current)
}
offStatus?.()
}
}, [probeBackend])

View File

@@ -11,7 +11,8 @@ const WindowControls: React.FC = () => {
useEffect(() => {
api?.windowIsMaximized().then(setMaximized)
api?.onMaximizeChange(setMaximized)
const off = api?.onMaximizeChange(setMaximized)
return off
}, [api])
if (api?.platform === 'darwin') return null

View File

@@ -8,14 +8,15 @@ export interface ElectronAPI {
restartBackend: () => Promise<boolean>
selectDirectory: () => Promise<string | null>
selectFile: (filters?: { name: string; extensions: string[] }[]) => Promise<string | null>
onBackendStatus: (callback: (data: BackendStatusEvent) => void) => void
onBackendLog: (callback: (line: string) => void) => void
// Listener registrars return an unsubscribe fn for cleanup.
onBackendStatus: (callback: (data: BackendStatusEvent) => void) => () => void
onBackendLog: (callback: (line: string) => void) => () => void
windowMinimize: () => Promise<void>
windowMaximize: () => Promise<boolean>
windowClose: () => Promise<void>
windowIsMaximized: () => Promise<boolean>
onMaximizeChange: (callback: (maximized: boolean) => void) => void
onMenuAction?: (callback: (action: string) => void) => void
onMaximizeChange: (callback: (maximized: boolean) => void) => () => void
onMenuAction?: (callback: (action: string) => void) => () => void
platform: string
}