1
This commit is contained in:
@@ -4,7 +4,7 @@ const config = require('./config.js');
|
|||||||
const deviceManager = require('./deviceManager.js');
|
const deviceManager = require('./deviceManager.js');
|
||||||
const command = require('./command.js');
|
const command = require('./command.js');
|
||||||
const db = require('../dbProxy');
|
const db = require('../dbProxy');
|
||||||
|
const Framework = require("../../../framework/node-core-framework.js");
|
||||||
/**
|
/**
|
||||||
* 检查当前时间是否在指定的时间范围内
|
* 检查当前时间是否在指定的时间范围内
|
||||||
* @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1}
|
* @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1}
|
||||||
@@ -99,6 +99,16 @@ class ScheduledJobs {
|
|||||||
this.jobs.push(timeoutCheckJob);
|
this.jobs.push(timeoutCheckJob);
|
||||||
console.log('[定时任务] 已启动任务超时检查任务');
|
console.log('[定时任务] 已启动任务超时检查任务');
|
||||||
|
|
||||||
|
// 启动任务状态摘要同步定时任务(每10秒发送一次)
|
||||||
|
const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => {
|
||||||
|
await this.syncTaskStatusSummary().catch(error => {
|
||||||
|
console.error('[定时任务] 同步任务状态摘要失败:', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.jobs.push(taskSummaryJob);
|
||||||
|
console.log('[定时任务] 已启动任务状态摘要同步任务');
|
||||||
|
|
||||||
|
|
||||||
// 执行自动投递任务
|
// 执行自动投递任务
|
||||||
const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => {
|
const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => {
|
||||||
@@ -275,6 +285,41 @@ class ScheduledJobs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步任务状态摘要到客户端
|
||||||
|
* 定期向所有在线设备发送任务状态摘要(当前任务、待执行任务、下次执行时间等)
|
||||||
|
*/
|
||||||
|
async syncTaskStatusSummary() {
|
||||||
|
try {
|
||||||
|
const { pla_account } = await Framework.getModels();
|
||||||
|
|
||||||
|
// 获取所有启用的账号
|
||||||
|
const accounts = await pla_account.findAll({
|
||||||
|
where: {
|
||||||
|
is_delete: 0,
|
||||||
|
is_enabled: 1
|
||||||
|
},
|
||||||
|
attributes: ['sn_code']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!accounts || accounts.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每个设备发送任务状态摘要
|
||||||
|
for (const account of accounts) {
|
||||||
|
const sn_code = account.sn_code;
|
||||||
|
try {
|
||||||
|
await this.taskQueue.sendTaskStatusSummary(sn_code);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[任务状态同步] 设备 ${sn_code} 同步失败:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[任务状态同步] 执行失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查任务超时并强制标记为失败
|
* 检查任务超时并强制标记为失败
|
||||||
* 检测长时间运行的任务(可能是卡住的),强制标记为失败,释放资源
|
* 检测长时间运行的任务(可能是卡住的),强制标记为失败,释放资源
|
||||||
|
|||||||
@@ -1054,6 +1054,113 @@ class TaskQueue {
|
|||||||
console.warn(`[任务队列] 通知客户端任务状态变更失败:`, error.message);
|
console.warn(`[任务队列] 通知客户端任务状态变更失败:`, error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务状态摘要(用于同步到客户端)
|
||||||
|
* @param {string} sn_code - 设备SN码
|
||||||
|
* @returns {Promise<object>} 任务状态摘要
|
||||||
|
*/
|
||||||
|
async getTaskStatusSummary(sn_code) {
|
||||||
|
try {
|
||||||
|
const queue = this.deviceQueues.get(sn_code);
|
||||||
|
const status = this.deviceStatus.get(sn_code) || {
|
||||||
|
isRunning: false,
|
||||||
|
currentTask: null,
|
||||||
|
runningCount: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取当前执行的任务
|
||||||
|
let currentTask = null;
|
||||||
|
if (status.currentTask) {
|
||||||
|
const taskData = status.currentTask;
|
||||||
|
currentTask = {
|
||||||
|
taskId: taskData.id,
|
||||||
|
taskName: taskData.taskName || taskData.task_name || taskData.taskType || taskData.task_type || '未知任务',
|
||||||
|
taskType: taskData.taskType || taskData.task_type,
|
||||||
|
status: 'running',
|
||||||
|
progress: taskData.progress || 0,
|
||||||
|
currentStep: taskData.currentStep || taskData.current_step || '',
|
||||||
|
startTime: taskData.startTime || taskData.start_time || taskData.created_time
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取待执行任务列表(最多10个)
|
||||||
|
const pendingTasks = [];
|
||||||
|
if (queue && queue.size() > 0) {
|
||||||
|
const queueArray = queue.toArray();
|
||||||
|
for (const task of queueArray.slice(0, 10)) {
|
||||||
|
const taskData = task;
|
||||||
|
pendingTasks.push({
|
||||||
|
taskId: taskData.id,
|
||||||
|
taskName: taskData.taskName || taskData.task_name || taskData.taskType || taskData.task_type || '未知任务',
|
||||||
|
taskType: taskData.taskType || taskData.task_type,
|
||||||
|
status: 'pending',
|
||||||
|
scheduledTime: taskData.scheduledTime || taskData.scheduled_time || taskData.created_time,
|
||||||
|
priority: taskData.priority || 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算下次任务执行时间(队列中第一个任务的计划时间)
|
||||||
|
let nextTaskTime = null;
|
||||||
|
if (queue && queue.size() > 0) {
|
||||||
|
const firstTask = queue.peek();
|
||||||
|
if (firstTask && (firstTask.scheduledTime || firstTask.scheduled_time)) {
|
||||||
|
nextTaskTime = firstTask.scheduledTime || firstTask.scheduled_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sn_code,
|
||||||
|
currentTask,
|
||||||
|
pendingTasks,
|
||||||
|
nextTaskTime,
|
||||||
|
pendingCount: queue ? queue.size() : 0,
|
||||||
|
mqttTopic: `task_status_${sn_code}`,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[任务队列] 获取任务状态摘要失败:`, error, { sn_code });
|
||||||
|
return {
|
||||||
|
sn_code,
|
||||||
|
currentTask: null,
|
||||||
|
pendingTasks: [],
|
||||||
|
nextTaskTime: null,
|
||||||
|
pendingCount: 0,
|
||||||
|
mqttTopic: `task_status_${sn_code}`,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向客户端发送任务状态摘要
|
||||||
|
* @param {string} sn_code - 设备SN码
|
||||||
|
*/
|
||||||
|
async sendTaskStatusSummary(sn_code) {
|
||||||
|
try {
|
||||||
|
const mqttClient = await this.getMqttClient();
|
||||||
|
if (!mqttClient) {
|
||||||
|
return; // MQTT客户端不可用,静默失败
|
||||||
|
}
|
||||||
|
|
||||||
|
const summary = await this.getTaskStatusSummary(sn_code);
|
||||||
|
|
||||||
|
// 通过MQTT发布任务状态摘要
|
||||||
|
// 主题格式: task_status_{sn_code}
|
||||||
|
const topic = `task_status_${sn_code}`;
|
||||||
|
const message = JSON.stringify({
|
||||||
|
action: 'task_status_summary',
|
||||||
|
data: summary,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
|
||||||
|
await mqttClient.publish(topic, message);
|
||||||
|
} catch (error) {
|
||||||
|
// 通知失败不影响任务执行,只记录日志
|
||||||
|
console.warn(`[任务队列] 发送任务状态摘要失败:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出单例
|
// 导出单例
|
||||||
|
|||||||
Reference in New Issue
Block a user