9.3 KiB
9.3 KiB
问题修复:批量发车超时 - 使用统一通信机制 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) // ❌ 超时
原因2:Promise 管理器状态不一致
- 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. 批量测试
- 打开批量自动化面板
- 选择2个账号(第2个账号待发车状态)
- 只勾选**"发车"**任务
- 点击"开始执行"
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)
如果修改后仍然超时,说明问题更深层:
- 可能是服务器端限制
- 可能需要增加账号间隔(5-10秒)
- 可能需要检查网络环境
但根据分析,v3.9.7应该能解决问题 ✅
📝 文件修改清单
修改文件
- ✅
src/stores/batchTaskStore.js- 第1152行:查询车辆
- 第1200行:刷新车辆
- 第1227行:刷新后重新查询
- 第1268行:收获车辆
- 第1298行:发送前最后查询
- 第1311行:发送车辆
新增文档
- ✅
MD说明/批量自动化发车流程分析v3.9.6.md- 流程分析文档 - ✅
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)
}
}
关键优势:
- ✅ 每次调用都重新获取
connection和client - ✅ 使用
wsConnections.value(响应式) - ✅ 检查
connection.status === 'connected' - ✅ 确保
client总是最新的
🎯 总结
问题本质
- 批量自动化复用
client对象 - 在等待和执行期间,
client可能失效 - 导致命令的 Promise 永远不会被 resolve
解决方案
- 统一使用
tokenStore.sendMessageAsync - 每次发送都获取最新的
client - 与游戏功能模块保持一致
预期结果
- ✅ 批量发车应该和单独测试一样快速成功
- ✅ 查询车辆应该在1-2秒内完成
- ✅ 整体流程顺畅可靠
🚀 下一步
- 重启开发服务器
- 批量测试2个账号
- 观察是否快速成功
- 享受批量发车的便利! 🎉
如果测试成功,说明问题已完美解决! ✅