343 lines
9.3 KiB
Markdown
343 lines
9.3 KiB
Markdown
# 问题修复:批量发车超时 - 使用统一通信机制 v3.9.7
|
||
|
||
## 🚀 概述
|
||
|
||
**问题**:
|
||
- ✅ 游戏功能模块单独测试:**成功且非常快**
|
||
- ❌ 批量自动化测试:**超时(20秒)**
|
||
|
||
**用户反馈**:
|
||
> "单独测试是成功的,而且查询的非常快"
|
||
|
||
**根本原因**:
|
||
- 批量自动化和游戏功能模块使用了**不同的通信机制**
|
||
- 批量自动化复用 `client` 对象,在等待和执行期间 `client` 可能失效
|
||
- 导致后续命令的 Promise 永远不会被 resolve
|
||
|
||
---
|
||
|
||
## 🔍 问题分析
|
||
|
||
### 之前的实现(v3.9.6及之前)
|
||
|
||
#### 游戏功能模块(成功✅)
|
||
```javascript
|
||
// CarManagement.vue
|
||
const response = await tokenStore.sendMessageAsync(
|
||
tokenId,
|
||
'car_getrolecar',
|
||
{},
|
||
10000
|
||
)
|
||
```
|
||
|
||
**特点**:
|
||
- ✅ 每次发送时获取最新的 `client`
|
||
- ✅ 使用响应式连接对象 `wsConnections.value[tokenId]`
|
||
- ✅ 简单可靠
|
||
|
||
---
|
||
|
||
#### 批量自动化(失败❌)
|
||
```javascript
|
||
// 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:等待期间连接被替换
|
||
```javascript
|
||
// 时间点 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行)
|
||
```diff
|
||
- const queryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
|
||
+ const queryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)
|
||
```
|
||
|
||
#### 修改2:刷新车辆(第1200行)
|
||
```diff
|
||
- await client.sendWithPromise('car_refresh', { carId: carId }, 5000)
|
||
+ await tokenStore.sendMessageAsync(tokenId, 'car_refresh', { carId: carId }, 5000)
|
||
```
|
||
|
||
#### 修改3:刷新后重新查询(第1227行)
|
||
```diff
|
||
- const reQueryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
|
||
+ const reQueryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)
|
||
```
|
||
|
||
#### 修改4:收获车辆(第1268行)
|
||
```diff
|
||
- await client.sendWithPromise('car_claim', { carId: carId }, 5000)
|
||
+ await tokenStore.sendMessageAsync(tokenId, 'car_claim', { carId: carId }, 5000)
|
||
```
|
||
|
||
#### 修改5:发送前最后查询(第1298行)
|
||
```diff
|
||
- const finalQueryResponse = await client.sendWithPromise('car_getrolecar', {}, 20000)
|
||
+ const finalQueryResponse = await tokenStore.sendMessageAsync(tokenId, 'car_getrolecar', {}, 20000)
|
||
```
|
||
|
||
#### 修改6:发送车辆(第1311行)
|
||
```diff
|
||
- 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. 重启开发服务器
|
||
```bash
|
||
# 在项目根目录
|
||
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 内部实现
|
||
|
||
```javascript
|
||
// 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秒内完成
|
||
- ✅ 整体流程顺畅可靠
|
||
|
||
---
|
||
|
||
## 🚀 下一步
|
||
|
||
1. **重启开发服务器**
|
||
2. **批量测试2个账号**
|
||
3. **观察是否快速成功**
|
||
4. **享受批量发车的便利!** 🎉
|
||
|
||
如果测试成功,说明问题已完美解决! ✅
|
||
|