1
This commit is contained in:
354
_doc/任务与指令的区别说明.md
Normal file
354
_doc/任务与指令的区别说明.md
Normal file
@@ -0,0 +1,354 @@
|
||||
# 任务与指令的区别说明
|
||||
|
||||
## 📋 概述
|
||||
|
||||
在调度系统中,**任务(Task)** 和 **指令(Command)** 是两个不同层次的概念,它们的关系是:**一个任务可以包含多个指令**。
|
||||
|
||||
### ⚠️ 重要说明
|
||||
|
||||
**当前系统实际情况**:
|
||||
- **真正的任务**:目前只有 `auto_deliver`(自动投递任务)是真正的任务,它包含多个步骤和指令
|
||||
- **伪任务**:虽然代码中有 `get_resume`、`get_job_list`、`send_chat`、`apply_job` 等任务处理器,但它们实际上只是包装了单个指令,本质上就是直接执行指令
|
||||
|
||||
**为什么会有伪任务**:
|
||||
1. 统一的任务追踪和日志记录
|
||||
2. 保持接口的一致性
|
||||
3. 未来可能扩展为真正的任务(包含多个步骤)
|
||||
|
||||
## 🔄 层级关系
|
||||
|
||||
```
|
||||
任务(Task)
|
||||
├── 指令1(Command)
|
||||
├── 指令2(Command)
|
||||
└── 指令3(Command)
|
||||
```
|
||||
|
||||
## 📊 详细对比
|
||||
|
||||
| 维度 | 任务(Task) | 指令(Command) |
|
||||
|------|------------|----------------|
|
||||
| **概念层级** | 业务层 | 执行层 |
|
||||
| **数据库表** | `task_status` | `task_commands` |
|
||||
| **管理模块** | TaskQueue(任务队列) | CommandManager(指令管理器) |
|
||||
| **处理模块** | TaskHandlers(任务处理器) | jobManager(业务管理器) |
|
||||
| **粒度** | 粗粒度(业务流程) | 细粒度(具体操作) |
|
||||
| **包含关系** | 包含多个指令 | 属于某个任务 |
|
||||
| **执行方式** | 由任务队列调度 | 由指令管理器执行 |
|
||||
| **通信方式** | 内部调度 | 通过 MQTT 发送到客户端 |
|
||||
|
||||
## 🎯 任务(Task)
|
||||
|
||||
### 定义
|
||||
任务是业务层面的概念,代表一个完整的业务流程或工作单元。
|
||||
|
||||
### 特点
|
||||
- **业务导向**:代表一个完整的业务目标
|
||||
- **可包含多个步骤**:一个任务可以包含多个指令
|
||||
- **有生命周期**:pending → running → completed/failed
|
||||
- **有优先级**:可以设置任务优先级
|
||||
- **有超时机制**:任务级别有超时保护
|
||||
|
||||
### 任务类型示例
|
||||
|
||||
**真正的任务(包含多个步骤)**:
|
||||
- `auto_deliver` - 自动投递任务(包含多个子操作:获取简历、获取岗位列表、筛选职位、批量投递)
|
||||
- `auto_chat` - 自动沟通任务(待实现:自动与HR进行沟通,回复消息等)
|
||||
- `auto_active_account` - 自动活跃账号任务(待实现:自动执行操作保持账号活跃度)
|
||||
|
||||
**注意**:目前系统中只有 `auto_deliver` 是已实现的真正任务,`auto_chat` 和 `auto_active_account` 是待实现的任务框架。
|
||||
|
||||
### 任务表结构(task_status)
|
||||
```javascript
|
||||
{
|
||||
id: 1,
|
||||
sn_code: 'GHJU',
|
||||
taskType: 'auto_deliver',
|
||||
taskName: '自动投递 - 前端开发',
|
||||
status: 'running',
|
||||
priority: 7,
|
||||
taskParams: { keyword: '前端', platform: 'boss' },
|
||||
result: {},
|
||||
startTime: '2024-01-01 10:00:00',
|
||||
endTime: null,
|
||||
duration: 0
|
||||
}
|
||||
```
|
||||
|
||||
### 任务执行流程
|
||||
```javascript
|
||||
// 1. 添加任务到队列
|
||||
await taskQueue.addTask(sn_code, {
|
||||
taskType: 'auto_deliver',
|
||||
taskName: '自动投递',
|
||||
taskParams: { keyword: '前端' }
|
||||
});
|
||||
|
||||
// 2. 任务队列调度执行
|
||||
// 3. 任务处理器处理任务
|
||||
// 4. 任务处理器创建并执行指令
|
||||
```
|
||||
|
||||
## ⚙️ 指令(Command)
|
||||
|
||||
### 定义
|
||||
指令是执行层面的概念,代表一个具体的操作,通过 MQTT 发送到客户端执行。
|
||||
|
||||
### 特点
|
||||
- **执行导向**:代表一个具体的操作
|
||||
- **原子性**:一个指令是一个不可分割的操作
|
||||
- **有执行顺序**:指令可以按顺序执行
|
||||
- **有超时机制**:指令级别有超时保护
|
||||
- **MQTT 通信**:通过 MQTT 发送到客户端
|
||||
|
||||
### 指令类型示例
|
||||
- `getOnlineResume` - 获取在线简历
|
||||
- `getJobList` - 获取岗位列表
|
||||
- `applyJob` - 投递简历
|
||||
- `sendChatMessage` - 发送聊天消息
|
||||
- `getLoginQrCode` - 获取登录二维码
|
||||
|
||||
### 指令表结构(task_commands)
|
||||
```javascript
|
||||
{
|
||||
id: 1,
|
||||
task_id: 100, // 关联的任务ID
|
||||
command_type: 'getOnlineResume',
|
||||
command_name: '获取在线简历',
|
||||
command_params: '{"sn_code":"GHJU"}',
|
||||
status: 'completed',
|
||||
sequence: 1,
|
||||
priority: 9,
|
||||
start_time: '2024-01-01 10:00:00',
|
||||
end_time: '2024-01-01 10:00:30',
|
||||
duration: 30000
|
||||
}
|
||||
```
|
||||
|
||||
### 指令执行流程
|
||||
```javascript
|
||||
// 1. 任务处理器创建指令
|
||||
const commands = [{
|
||||
command_type: 'getOnlineResume',
|
||||
command_name: '获取在线简历',
|
||||
command_params: JSON.stringify({ sn_code })
|
||||
}];
|
||||
|
||||
// 2. 指令管理器执行指令
|
||||
await command.executeCommands(taskId, commands, mqttClient);
|
||||
|
||||
// 3. 通过 MQTT 发送到客户端
|
||||
// 4. 客户端执行并返回结果
|
||||
```
|
||||
|
||||
## 🔗 关系示例
|
||||
|
||||
### 示例1:自动投递任务
|
||||
|
||||
**任务**:`auto_deliver`(自动投递任务)
|
||||
|
||||
**包含的指令**:
|
||||
1. `getOnlineResume` - 获取在线简历
|
||||
2. `getJobList` - 获取岗位列表
|
||||
3. `applyJob` - 投递简历(可能多个)
|
||||
|
||||
```javascript
|
||||
// 任务处理器创建多个指令
|
||||
async handleAutoDeliverTask(task) {
|
||||
// 1. 获取简历指令
|
||||
const getResumeCommand = {
|
||||
command_type: 'getOnlineResume',
|
||||
command_name: '获取在线简历',
|
||||
...
|
||||
};
|
||||
|
||||
// 2. 获取岗位列表指令
|
||||
const getJobListCommand = {
|
||||
command_type: 'getJobList',
|
||||
command_name: '获取岗位列表',
|
||||
...
|
||||
};
|
||||
|
||||
// 3. 投递指令(可能多个)
|
||||
const applyCommands = jobs.map(job => ({
|
||||
command_type: 'applyJob',
|
||||
command_name: `投递简历 - ${job.jobTitle}`,
|
||||
...
|
||||
}));
|
||||
|
||||
// 执行所有指令
|
||||
await command.executeCommands(task.id, [
|
||||
getResumeCommand,
|
||||
getJobListCommand,
|
||||
...applyCommands
|
||||
], mqttClient);
|
||||
}
|
||||
```
|
||||
|
||||
### 示例2:获取简历(伪任务,实际是指令)
|
||||
|
||||
**说明**:虽然代码中有 `get_resume` 任务处理器,但它实际上只是包装了单个指令,本质上就是直接执行指令。
|
||||
|
||||
**任务**:`get_resume`(获取简历任务)
|
||||
|
||||
**包含的指令**:
|
||||
1. `getOnlineResume` - 获取在线简历
|
||||
|
||||
```javascript
|
||||
async handleGetResumeTask(task) {
|
||||
// 实际上只是创建一个指令并执行
|
||||
const commands = [{
|
||||
command_type: 'getOnlineResume',
|
||||
command_name: '获取在线简历',
|
||||
command_params: JSON.stringify({ sn_code: task.sn_code })
|
||||
}];
|
||||
|
||||
await command.executeCommands(task.id, commands, this.mqttClient);
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:这种"任务"实际上可以直接作为指令执行,不需要通过任务队列。它们存在的原因可能是为了:
|
||||
1. 统一的任务追踪和日志记录
|
||||
2. 未来可能扩展为真正的任务(包含多个步骤)
|
||||
3. 保持接口的一致性
|
||||
|
||||
## 📈 执行流程图
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 任务队列 │
|
||||
│ (TaskQueue) │
|
||||
└────────┬────────┘
|
||||
│ 调度任务
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ 任务处理器 │
|
||||
│ (TaskHandlers) │
|
||||
└────────┬────────┘
|
||||
│ 创建指令
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ 指令管理器 │
|
||||
│ (CommandManager)│
|
||||
└────────┬────────┘
|
||||
│ 执行指令
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ 业务管理器 │
|
||||
│ (jobManager) │
|
||||
└────────┬────────┘
|
||||
│ MQTT 发送
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ 客户端设备 │
|
||||
│ (Python Client)│
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## 🎨 设计优势
|
||||
|
||||
### 1. **职责分离**
|
||||
- **任务层**:负责业务逻辑和流程编排
|
||||
- **指令层**:负责具体操作和 MQTT 通信
|
||||
|
||||
### 2. **灵活性**
|
||||
- 一个任务可以包含不同数量的指令
|
||||
- 可以根据业务需求动态创建指令
|
||||
|
||||
### 3. **可追踪性**
|
||||
- 任务级别:可以追踪整个业务流程
|
||||
- 指令级别:可以追踪每个具体操作
|
||||
|
||||
### 4. **错误处理**
|
||||
- 任务级别:处理业务逻辑错误
|
||||
- 指令级别:处理执行错误和超时
|
||||
|
||||
## 📝 代码示例
|
||||
|
||||
### 任务处理器创建指令
|
||||
|
||||
```javascript
|
||||
// api/middleware/schedule/taskHandlers.js
|
||||
async handleAutoDeliverTask(task) {
|
||||
const { sn_code, taskParams } = task;
|
||||
|
||||
// 1. 创建获取简历指令
|
||||
const getResumeCommand = {
|
||||
command_type: 'getOnlineResume',
|
||||
command_name: '获取在线简历',
|
||||
command_params: JSON.stringify({ sn_code, platform: 'boss' })
|
||||
};
|
||||
|
||||
// 2. 创建获取岗位列表指令
|
||||
const getJobListCommand = {
|
||||
command_type: 'getJobList',
|
||||
command_name: '获取岗位列表',
|
||||
command_params: JSON.stringify({
|
||||
sn_code,
|
||||
keyword: taskParams.keyword,
|
||||
platform: 'boss'
|
||||
})
|
||||
};
|
||||
|
||||
// 3. 执行指令序列
|
||||
const result = await command.executeCommands(
|
||||
task.id,
|
||||
[getResumeCommand, getJobListCommand],
|
||||
this.mqttClient
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### 指令管理器执行指令
|
||||
|
||||
```javascript
|
||||
// api/middleware/schedule/command.js
|
||||
async executeCommand(taskId, command, mqttClient) {
|
||||
// 1. 创建指令记录
|
||||
const commandRecord = await db.getModel('task_commands').create({
|
||||
task_id: taskId,
|
||||
command_type: command.command_type,
|
||||
command_name: command.command_name,
|
||||
status: 'pending'
|
||||
});
|
||||
|
||||
// 2. 调用业务管理器执行
|
||||
const result = await jobManager[commandType](
|
||||
sn_code,
|
||||
mqttClient,
|
||||
commandParams
|
||||
);
|
||||
|
||||
// 3. 更新指令状态
|
||||
await this.updateCommandStatus(commandId, 'completed', result);
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 总结
|
||||
|
||||
- **任务(Task)**:业务层面的工作单元,代表一个完整的业务流程
|
||||
- **真正的任务**:包含多个步骤/指令,如 `auto_deliver`
|
||||
- **伪任务**:虽然叫任务,但实际只是包装了单个指令,如 `get_resume`、`get_job_list` 等
|
||||
|
||||
- **指令(Command)**:执行层面的操作单元,代表一个具体的操作
|
||||
- 通过 MQTT 发送到客户端执行
|
||||
- 如:`getOnlineResume`、`getJobList`、`applyJob` 等
|
||||
|
||||
- **关系**:
|
||||
- 真正的任务包含多个指令,指令按顺序执行
|
||||
- 伪任务只是指令的包装,本质上就是直接执行指令
|
||||
|
||||
- **管理**:任务由任务队列管理,指令由指令管理器管理
|
||||
|
||||
- **通信**:任务在服务端内部调度,指令通过 MQTT 发送到客户端
|
||||
|
||||
- **当前状态**:
|
||||
- 目前系统中只有 `auto_deliver` 是真正的任务(包含多个步骤)
|
||||
- 其他如 `get_resume`、`get_job_list`、`send_chat`、`apply_job` 虽然叫任务,但实际只是指令的包装
|
||||
|
||||
这种设计实现了业务逻辑和执行逻辑的分离,提高了系统的灵活性和可维护性。伪任务的存在可能是为了统一的任务追踪和未来扩展。
|
||||
|
||||
123
_doc/指令和任务模式适配检查报告.md
Normal file
123
_doc/指令和任务模式适配检查报告.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 指令和任务模式适配检查报告
|
||||
|
||||
## 📋 检查范围
|
||||
检查 `api/middleware` 目录下的代码是否适用于新的指令和任务模式。
|
||||
|
||||
## ✅ 已适配的部分
|
||||
|
||||
### 1. **任务处理器 (taskHandlers.js)**
|
||||
- ✅ 正确使用 `command.executeCommands()` 执行指令
|
||||
- ✅ 在 `handleAutoDeliverTask` 中创建指令并执行
|
||||
- ✅ 指令类型使用驼峰命名(`getOnlineResume`, `getJobList`, `applyJob`)
|
||||
|
||||
### 2. **指令管理器 (command.js)**
|
||||
- ✅ 已重构完成,统一封装指令执行
|
||||
- ✅ 统一处理成功、失败、超时
|
||||
- ✅ 统一记录数据库
|
||||
- ✅ 支持驼峰转下划线的命名转换
|
||||
|
||||
### 3. **任务队列 (taskQueue.js)**
|
||||
- ✅ 正确使用任务处理器
|
||||
- ✅ 通过 `taskHandlers` 执行任务
|
||||
|
||||
## ⚠️ 需要修复的问题
|
||||
|
||||
### 1. **方法命名不一致**
|
||||
|
||||
**问题描述**:
|
||||
- 指令类型使用驼峰命名:`getOnlineResume`, `getJobList`, `applyJob`
|
||||
- 大部分方法使用下划线命名:`get_online_resume`, `get_job_list`
|
||||
- 但 `applyJob` 方法名是驼峰命名,与指令类型一致
|
||||
|
||||
**当前转换逻辑**:
|
||||
```javascript
|
||||
// command.js 中的转换
|
||||
const to_snake_case = (str) => {
|
||||
if (str.includes('_')) return str;
|
||||
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
|
||||
};
|
||||
|
||||
// getOnlineResume -> get_online_resume ✓
|
||||
// getJobList -> get_job_list ✓
|
||||
// applyJob -> apply_job ✗ (但实际方法名是 applyJob)
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
1. **方案1(推荐)**:统一使用下划线命名,将 `applyJob` 改为 `apply_job`
|
||||
2. **方案2**:保持现状,`command.js` 中已支持两种命名方式(先尝试下划线,再尝试原名称)
|
||||
|
||||
**当前状态**:方案2已实现,代码可以正常工作,但命名不统一。
|
||||
|
||||
### 2. **sendChatMessage 方法**
|
||||
|
||||
**问题描述**:
|
||||
- `chatManager.js` 中的方法是 `sendChatMessage`(驼峰命名)
|
||||
- 如果指令类型是 `sendChatMessage`,转换后会变成 `send_chat_message`,但实际方法名是 `sendChatMessage`
|
||||
|
||||
**当前状态**:`command.js` 中已支持回退机制,如果下划线命名找不到,会尝试原名称,所以可以正常工作。
|
||||
|
||||
## 📊 方法命名对照表
|
||||
|
||||
| 指令类型 (command_type) | 转换后方法名 | 实际方法名 | 状态 |
|
||||
|------------------------|-------------|-----------|------|
|
||||
| `getOnlineResume` | `get_online_resume` | `get_online_resume` | ✅ 匹配 |
|
||||
| `getJobList` | `get_job_list` | `get_job_list` | ✅ 匹配 |
|
||||
| `applyJob` | `apply_job` | `applyJob` | ⚠️ 不匹配(但可工作) |
|
||||
| `sendChatMessage` | `send_chat_message` | `sendChatMessage` | ⚠️ 不匹配(但可工作) |
|
||||
|
||||
## 🔧 建议修复
|
||||
|
||||
### 方案1:统一使用下划线命名(推荐)
|
||||
|
||||
**修改文件**:
|
||||
1. `api/middleware/job/jobManager.js`:将 `applyJob` 改为 `apply_job`
|
||||
2. `api/middleware/job/chatManager.js`:将 `sendChatMessage` 改为 `send_chat_message`
|
||||
3. `api/middleware/schedule/taskHandlers.js`:将指令类型改为下划线命名
|
||||
|
||||
**优点**:
|
||||
- 命名统一,符合项目规范
|
||||
- 代码更清晰,减少混淆
|
||||
|
||||
**缺点**:
|
||||
- 需要修改多个文件
|
||||
- 可能影响其他调用方
|
||||
|
||||
### 方案2:保持现状(当前方案)
|
||||
|
||||
**优点**:
|
||||
- 不需要修改现有代码
|
||||
- `command.js` 已支持两种命名方式
|
||||
|
||||
**缺点**:
|
||||
- 命名不统一,容易混淆
|
||||
- 代码可读性稍差
|
||||
|
||||
## 📝 其他检查项
|
||||
|
||||
### 1. **deviceManager.js**
|
||||
- ✅ 不直接涉及指令和任务,主要用于设备状态管理
|
||||
- ✅ 与任务系统配合良好
|
||||
|
||||
### 2. **job/index.js**
|
||||
- ✅ 正确导出所有方法
|
||||
- ✅ 支持下划线命名规范
|
||||
|
||||
### 3. **MQTT 相关**
|
||||
- ✅ 通过 `mqttClient.publishAndWait` 发送指令
|
||||
- ✅ 与指令系统配合良好
|
||||
|
||||
## ✅ 总结
|
||||
|
||||
**整体适配情况**:**良好** ✅
|
||||
|
||||
1. ✅ 核心功能已正确适配新的指令和任务模式
|
||||
2. ✅ 指令执行统一封装,处理逻辑完善
|
||||
3. ⚠️ 存在命名不一致问题,但不影响功能(有回退机制)
|
||||
4. 💡 建议统一命名规范,提高代码可维护性
|
||||
|
||||
## 🎯 下一步行动
|
||||
|
||||
1. **可选**:统一方法命名规范(下划线命名)
|
||||
2. **可选**:添加单元测试验证指令执行流程
|
||||
3. **可选**:完善错误处理和日志记录
|
||||
|
||||
Reference in New Issue
Block a user