10 KiB
10 KiB
任务与指令的区别说明
📋 概述
在调度系统中,任务(Task) 和 指令(Command) 是两个不同层次的概念,它们的关系是:一个任务可以包含多个指令。
⚠️ 重要说明
当前系统实际情况:
- 真正的任务:目前只有
auto_deliver(自动投递任务)是真正的任务,它包含多个步骤和指令 - 伪任务:虽然代码中有
get_resume、get_job_list、send_chat、apply_job等任务处理器,但它们实际上只是包装了单个指令,本质上就是直接执行指令
为什么会有伪任务:
- 统一的任务追踪和日志记录
- 保持接口的一致性
- 未来可能扩展为真正的任务(包含多个步骤)
🔄 层级关系
任务(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)
{
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
}
任务执行流程
// 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)
{
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
}
指令执行流程
// 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(自动投递任务)
包含的指令:
getOnlineResume- 获取在线简历getJobList- 获取岗位列表applyJob- 投递简历(可能多个)
// 任务处理器创建多个指令
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(获取简历任务)
包含的指令:
getOnlineResume- 获取在线简历
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);
}
注意:这种"任务"实际上可以直接作为指令执行,不需要通过任务队列。它们存在的原因可能是为了:
- 统一的任务追踪和日志记录
- 未来可能扩展为真正的任务(包含多个步骤)
- 保持接口的一致性
📈 执行流程图
┌─────────────────┐
│ 任务队列 │
│ (TaskQueue) │
└────────┬────────┘
│ 调度任务
↓
┌─────────────────┐
│ 任务处理器 │
│ (TaskHandlers) │
└────────┬────────┘
│ 创建指令
↓
┌─────────────────┐
│ 指令管理器 │
│ (CommandManager)│
└────────┬────────┘
│ 执行指令
↓
┌─────────────────┐
│ 业务管理器 │
│ (jobManager) │
└────────┬────────┘
│ MQTT 发送
↓
┌─────────────────┐
│ 客户端设备 │
│ (Python Client)│
└─────────────────┘
🎨 设计优势
1. 职责分离
- 任务层:负责业务逻辑和流程编排
- 指令层:负责具体操作和 MQTT 通信
2. 灵活性
- 一个任务可以包含不同数量的指令
- 可以根据业务需求动态创建指令
3. 可追踪性
- 任务级别:可以追踪整个业务流程
- 指令级别:可以追踪每个具体操作
4. 错误处理
- 任务级别:处理业务逻辑错误
- 指令级别:处理执行错误和超时
📝 代码示例
任务处理器创建指令
// 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;
}
指令管理器执行指令
// 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虽然叫任务,但实际只是指令的包装
- 目前系统中只有
这种设计实现了业务逻辑和执行逻辑的分离,提高了系统的灵活性和可维护性。伪任务的存在可能是为了统一的任务追踪和未来扩展。