Files
dify_market_manager_gui/EXIT_FUNCTION_FIX.md
2025-07-22 17:53:26 +08:00

6.3 KiB
Raw Blame History

应用退出功能修复说明

问题描述

点击系统托盘区的"退出"时,任务管理器里面还有残余进程没有完全退出,导致再次点击图标时打不开应用程序。

问题原因分析

  1. 退出方法不当:使用了 app.quit() 而不是 app.exit(),导致应用没有完全退出
  2. 窗口销毁不完整:窗口销毁和进程退出之间没有足够的延迟
  3. 退出事件处理不当:多个退出事件处理器可能相互冲突
  4. 进程残留:应用异常退出时,子进程没有正确清理

修复内容

1. 修复托盘退出功能 (src/main/tray.js)

修复前:

{
  label: '退出应用',
  click: () => {
    app.isQuiting = true
    // 确保所有窗口都被关闭
    BrowserWindow.getAllWindows().forEach(window => {
      window.destroy()
    })
    app.quit()
  }
}

修复后:

{
  label: '退出应用',
  click: () => {
    logger.info('用户点击退出应用')
    app.isQuiting = true
    
    // 确保所有窗口都被关闭
    const windows = BrowserWindow.getAllWindows()
    logger.info(`准备关闭 ${windows.length} 个窗口`)
    
    windows.forEach(window => {
      if (!window.isDestroyed()) {
        try {
          window.destroy()
          logger.info('窗口销毁成功')
        } catch (error) {
          logger.warn('销毁窗口时出错:', error)
        }
      }
    })
    
    // 延迟执行退出,确保窗口销毁完成
    setTimeout(() => {
      try {
        logger.info('执行应用退出')
        // 使用 exit 而不是 quit确保完全退出
        app.exit(0)
      } catch (error) {
        logger.error('应用退出失败,尝试强制退出:', error)
        try {
          process.exit(0)
        } catch (processError) {
          logger.error('强制退出也失败:', processError)
          // 最后的强制退出
          process.kill(process.pid, 'SIGKILL')
        }
      }
    }, 500) // 延迟500ms确保窗口销毁完成
  }
}

2. 修复主进程退出逻辑 (src/main/index.js)

修复前:

app.on('window-all-closed', async (event) => {
  // ...
  if (!app.isQuiting) {
    // 隐藏窗口
    app.quit()
  } else {
    // 主动退出
    app.quit()
  }
})

app.on('before-quit', async (event) => {
  // ...
  app.quit()
})

app.on('will-quit', async (event) => {
  // ...
  app.quit()
})

修复后:

app.on('window-all-closed', async (event) => {
  // ...
  if (!app.isQuiting) {
    logger.info('用户关闭窗口,隐藏应用')
    // 隐藏窗口
    app.quit()
  } else {
    logger.info('主动退出,完全关闭应用')
    // 使用 exit 确保完全退出
    app.exit(0)
  }
})

app.on('before-quit', async (event) => {
  logger.info('应用即将退出,开始清理资源')
  // ...
  // 使用 exit 确保完全退出
  app.exit(0)
})

app.on('will-quit', async (event) => {
  logger.info('应用即将退出,注销快捷键')
  // ...
  // 使用 exit 确保完全退出
  app.exit(0)
})

3. 创建清理工具

force-kill-processes.js - 强制清理进程脚本

// 查找并终止所有相关进程
const processes = [
  '龙岗区百千万AI智能体共创平台.exe',
  'dify-market-manager-gui.exe',
  'electron.exe'
]

for (const processName of processes) {
  // 查找进程
  const findResult = execSync(`tasklist /FI "IMAGENAME eq ${processName}" /FO CSV /NH`)
  
  if (findResult.includes(processName)) {
    // 终止进程
    execSync(`taskkill /F /IM "${processName}"`)
  }
}

test-exit-function.js - 退出功能测试脚本

// 测试托盘退出功能
{
  label: '退出应用',
  click: () => {
    console.log('用户点击退出应用')
    
    // 确保所有窗口都被关闭
    const windows = BrowserWindow.getAllWindows()
    windows.forEach(window => {
      if (!window.isDestroyed()) {
        window.destroy()
      }
    })
    
    // 延迟执行退出
    setTimeout(() => {
      app.exit(0)
    }, 500)
  }
}

修复后的功能特点

1. 完全退出

  • 使用 app.exit(0) 替代 app.quit()
  • 确保所有窗口完全销毁后再退出
  • 添加延迟确保资源清理完成

2. 多层退出保护

  • 托盘退出:app.exit(0)
  • 主进程退出:app.exit(0)
  • 异常退出:process.exit(0)
  • 强制退出:process.kill(process.pid, 'SIGKILL')

3. 详细日志记录

  • 记录退出过程的每个步骤
  • 便于调试和问题排查
  • 区分不同类型的退出

4. 进程清理工具

  • 自动查找相关进程
  • 强制终止残留进程
  • 验证清理结果

使用方法

1. 正常退出

  1. 右键点击系统托盘图标
  2. 选择"退出应用"
  3. 应用将完全退出,无进程残留

2. 清理残留进程

# 强制清理所有相关进程
node force-kill-processes.js

# 清理锁文件
node cleanup-lock-files.js

3. 测试退出功能

# 运行测试脚本
node test-exit-function.js

验证修复效果

1. 正常退出

[时间] 用户点击退出应用
[时间] 准备关闭 1 个窗口
[时间] 窗口销毁成功
[时间] 执行应用退出

2. 进程检查

# 检查是否还有相关进程
tasklist /FI "IMAGENAME eq 龙岗区百千万AI智能体共创平台.exe"
# 应该显示INFO: No tasks are running which match the specified criteria.

3. 重新启动

  • 退出后重新点击应用图标
  • 应该能正常启动,无单实例冲突

注意事项

1. 退出时机

  • 确保所有窗口完全销毁后再退出
  • 添加适当的延迟避免资源冲突

2. 异常处理

  • 提供多层退出保护机制
  • 记录详细的退出日志

3. 进程清理

  • 定期检查是否有残留进程
  • 使用清理工具处理异常情况

相关文件

  • src/main/tray.js - 托盘功能(已修复退出逻辑)
  • src/main/index.js - 主进程(已修复退出事件)
  • force-kill-processes.js - 强制清理进程脚本
  • test-exit-function.js - 退出功能测试脚本
  • cleanup-lock-files.js - 锁文件清理脚本

总结

通过使用 app.exit(0) 替代 app.quit()、添加窗口销毁延迟、提供多层退出保护机制,成功解决了应用退出时进程残留的问题。现在点击托盘"退出应用"后,应用将完全退出,无进程残留,可以正常重新启动。