# 任务与指令的区别说明 ## 📋 概述 在调度系统中,**任务(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` 虽然叫任务,但实际只是指令的包装 这种设计实现了业务逻辑和执行逻辑的分离,提高了系统的灵活性和可维护性。伪任务的存在可能是为了统一的任务追踪和未来扩展。