Files
xyzw_web_helper/MD说明文件夹/问题修复-批量发车超时使用统一通信机制v3.9.7.md
2025-10-17 20:56:50 +08:00

9.3 KiB
Raw Blame History

问题修复:批量发车超时 - 使用统一通信机制 v3.9.7

🚀 概述

问题

  • 游戏功能模块单独测试:成功且非常快
  • 批量自动化测试:超时20秒

用户反馈

"单独测试是成功的,而且查询的非常快"

根本原因

  • 批量自动化和游戏功能模块使用了不同的通信机制
  • 批量自动化复用 client 对象,在等待和执行期间 client 可能失效
  • 导致后续命令的 Promise 永远不会被 resolve

🔍 问题分析

之前的实现v3.9.6及之前)

游戏功能模块(成功

// CarManagement.vue
const response = await tokenStore.sendMessageAsync(
  tokenId,
  'car_getrolecar',
  {},
  10000
)

特点

  • 每次发送时获取最新的 client
  • 使用响应式连接对象 wsConnections.value[tokenId]
  • 简单可靠

批量自动化(失败

// batchTaskStore.js (v3.9.6)
const client = await ensureConnection(tokenId)  // 获取一次
await new Promise(resolve => setTimeout(resolve, 2000))  // 等待2秒

// 后续多次使用这个 client
await client.sendWithPromise('car_getrolecar', {}, 20000)  // ❌ 可能失效
await client.sendWithPromise('car_refresh', { carId }, 5000)  // ❌ 可能失效
await client.sendWithPromise('car_claim', { carId }, 5000)  // ❌ 可能失效
await client.sendWithPromise('car_send', { carId }, 5000)  // ❌ 可能失效

问题

  • 一次性获取 client 后长时间复用
  • 在等待期间2秒和执行期间client 可能失效
  • 使用非响应式连接对象 tokenStore.wsConnections[tokenId]

为什么 client 会失效?

原因1等待期间连接被替换

// 时间点 T0: 获取 client
const client = await ensureConnection(tokenId)

// 时间点 T0 → T2: 等待2秒
await new Promise(resolve => setTimeout(resolve, 2000))

// 时间点 T2: client 可能已经失效
// - 连接可能被重置
// - tokenStore.reconnectWebSocket 可能创建了新的 client
// - 旧的 client 引用失效
await client.sendWithPromise('car_getrolecar', {}, 20000)  // ❌ 超时

原因2Promise 管理器状态不一致

  • WebSocket client 内部有 Promise 管理器
  • 如果连接重置Promise 管理器也会重置
  • 旧的 Promise 永远不会被 resolve

原因3事件监听器失效

  • WebSocket client 依赖 onmessage 事件
  • 连接重置后,旧的事件监听器失效
  • 新消息不会触发旧 client 的 Promise resolve

🛠️ 解决方案 v3.9.7

核心改进:统一使用 tokenStore.sendMessageAsync

不再复用 client 对象,每次发送时都获取最新的 client


修改详情

修改1查询车辆第1152行

- const queryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
+ const queryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)

修改2刷新车辆第1200行

- await client.sendWithPromise('car_refresh', { carId: carId }, 5000)
+ await tokenStore.sendMessageAsync(tokenId, 'car_refresh', { carId: carId }, 5000)

修改3刷新后重新查询第1227行

- const reQueryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
+ const reQueryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)

修改4收获车辆第1268行

- await client.sendWithPromise('car_claim', { carId: carId }, 5000)
+ await tokenStore.sendMessageAsync(tokenId, 'car_claim', { carId: carId }, 5000)

修改5发送前最后查询第1298行

- const finalQueryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
+ const finalQueryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)

修改6发送车辆第1311行

- await client.sendWithPromise('car_send', { carId, helperId: 0, text: "" }, 5000)
+ await tokenStore.sendMessageAsync(tokenId, 'car_send', { carId, helperId: 0, text: "" }, 5000)

优势

1. 统一通信机制

  • 批量自动化与游戏功能模块使用相同的通信机制
  • 代码一致性和可维护性大幅提升

2. 每次获取最新 client

  • 每次发送命令时都通过 wsConnections.value[tokenId] 获取最新的 client
  • 避免 client 对象失效问题

3. 使用响应式状态

  • wsConnections.value[tokenId] 是响应式的
  • 总是获取到最新的连接状态

4. 简单可靠

  • 逻辑更简单清晰
  • 与游戏功能模块保持一致
  • 避免复杂的 client 管理

📊 预期效果

v3.9.6(修改前)

✅ WebSocket连接成功
⏳ 等待连接稳定... (2秒)
📤 发送消息: car_getrolecar {}
💓 心跳消息... (不断收发)
❌ 20秒后超时没有收到 car_getrolecarresp

问题client 对象在等待期间失效


v3.9.7(修改后)

✅ WebSocket连接成功
⏳ 等待连接稳定... (2秒)
📤 发送消息: car_getrolecar {}
✅ 收到响应: car_getrolecarresp (1-2秒内)  ← 预期快速成功
✅ [token_xxx] 查询到 4 辆车

改进:每次发送都获取最新的 client避免失效


🧪 验证步骤

1. 重启开发服务器

# 在项目根目录
npm run dev

2. 批量测试

  1. 打开批量自动化面板
  2. 选择2个账号第2个账号待发车状态
  3. 只勾选**"发车"**任务
  4. 点击"开始执行"

3. 观察结果

期望结果(成功

🎯 开始执行 Token: 805服-0-xxx
✅ WebSocket连接成功
⏳ 等待连接稳定...
📌 执行任务 [1/1]: sendCar
🚗 [token_xxx] 开始查询俱乐部车辆...
✅ [token_xxx] 查询到 4 辆车  ← 应该1-2秒内完成
🔄 [token_xxx] 开始批量刷新车辆...
✅ [token_xxx] 刷新车辆成功: carId
🎁 [token_xxx] 开始批量收获...
✅ [token_xxx] 收获车辆成功: carId
🚀 [token_xxx] 开始批量发送...
✅ [token_xxx] 发送车辆成功: carId
✅ Token完成: 805服-0-xxx

⏳ Token token_xxx 将在 3.0秒 后建立连接  ← 串行执行

🎯 开始执行 Token: 805服-1-xxx
✅ WebSocket连接成功
⏳ 等待连接稳定...
📌 执行任务 [1/1]: sendCar
🚗 [token_xxx] 开始查询俱乐部车辆...
✅ [token_xxx] 查询到 4 辆车  ← 应该1-2秒内完成
✅ Token完成: 805服-1-xxx

📊 统计信息: {total: 2, success: 2, failed: 0}  ✅

关键指标

  • 查询车辆应该在1-2秒内完成而不是20秒超时
  • 每个步骤都能快速响应
  • 整体流程顺畅

如果仍然失败unlikely

如果修改后仍然超时,说明问题更深层:

  1. 可能是服务器端限制
  2. 可能需要增加账号间隔5-10秒
  3. 可能需要检查网络环境

但根据分析,v3.9.7应该能解决问题


📝 文件修改清单

修改文件

  1. src/stores/batchTaskStore.js
    • 第1152行查询车辆
    • 第1200行刷新车辆
    • 第1227行刷新后重新查询
    • 第1268行收获车辆
    • 第1298行发送前最后查询
    • 第1311行发送车辆

新增文档

  1. MD说明/批量自动化发车流程分析v3.9.6.md - 流程分析文档
  2. MD说明/问题修复-批量发车超时使用统一通信机制v3.9.7.md - 本文档

🔄 版本信息

  • 版本号v3.9.7
  • 修复日期2025-10-08
  • 影响范围:批量自动化 - 发车任务
  • 向后兼容 完全兼容
  • 破坏性变更

💡 技术要点

tokenStore.sendMessageAsync 内部实现

// src/stores/tokenStore.js 第1414-1430行
const sendMessageWithPromise = async (tokenId, cmd, params = {}, timeout = 1000) => {
  // 1. 获取最新的连接对象(响应式)
  const connection = wsConnections.value[tokenId]
  
  // 2. 检查连接状态
  if (!connection || connection.status !== 'connected') {
    return Promise.reject(new Error(`WebSocket未连接 [${tokenId}]`))
  }
  
  // 3. 获取最新的 client
  const client = connection.client
  if (!client) {
    return Promise.reject(new Error(`WebSocket客户端不存在 [${tokenId}]`))
  }
  
  // 4. 发送命令
  try {
    return await client.sendWithPromise(cmd, params, timeout)
  } catch (error) {
    return Promise.reject(error)
  }
}

关键优势

  • 每次调用都重新获取 connectionclient
  • 使用 wsConnections.value(响应式)
  • 检查 connection.status === 'connected'
  • 确保 client 总是最新的

🎯 总结

问题本质

  • 批量自动化复用 client 对象
  • 在等待和执行期间,client 可能失效
  • 导致命令的 Promise 永远不会被 resolve

解决方案

  • 统一使用 tokenStore.sendMessageAsync
  • 每次发送都获取最新的 client
  • 与游戏功能模块保持一致

预期结果

  • 批量发车应该和单独测试一样快速成功
  • 查询车辆应该在1-2秒内完成
  • 整体流程顺畅可靠

🚀 下一步

  1. 重启开发服务器
  2. 批量测试2个账号
  3. 观察是否快速成功
  4. 享受批量发车的便利! 🎉

如果测试成功,说明问题已完美解决!