From 63ae5ffbab2d7a4a5a49a82bdb710c0997aaddc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Tue, 16 Dec 2025 14:01:37 +0800 Subject: [PATCH] 1 --- api/middleware/schedule/scheduledJobs.js | 42 ++++++++++++++++ api/middleware/schedule/taskQueue.js | 62 +++++++++++++++++++++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/api/middleware/schedule/scheduledJobs.js b/api/middleware/schedule/scheduledJobs.js index c97690d..3ab2088 100644 --- a/api/middleware/schedule/scheduledJobs.js +++ b/api/middleware/schedule/scheduledJobs.js @@ -466,6 +466,27 @@ class ScheduledJobs { for (const pl_user of pla_users) { const userData = pl_user.toJSON(); + // 检查设备是否在线(离线阈值:3分钟) + const offlineThreshold = 3 * 60 * 1000; // 3分钟 + const now = Date.now(); + const device = deviceManager.devices.get(userData.sn_code); + + if (!device) { + // 设备从未发送过心跳,视为离线 + console.log(`[自动投递] 设备 ${userData.sn_code} 离线(从未发送心跳),跳过添加任务`); + continue; + } + + // 检查最后心跳时间 + const lastHeartbeat = device.lastHeartbeat || 0; + const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); + + if (!isOnline) { + const offlineMinutes = lastHeartbeat ? Math.round((now - lastHeartbeat) / (60 * 1000)) : '未知'; + console.log(`[自动投递] 设备 ${userData.sn_code} 离线(最后心跳: ${offlineMinutes}分钟前),跳过添加任务`); + continue; + } + // 检查设备调度策略 const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'deliver'); if (!canExecute.allowed) { @@ -599,6 +620,27 @@ class ScheduledJobs { for (const pl_user of pla_users) { const userData = pl_user.toJSON(); + // 检查设备是否在线(离线阈值:3分钟) + const offlineThreshold = 3 * 60 * 1000; // 3分钟 + const now = Date.now(); + const device = deviceManager.devices.get(userData.sn_code); + + if (!device) { + // 设备从未发送过心跳,视为离线 + console.log(`[自动沟通] 设备 ${userData.sn_code} 离线(从未发送心跳),跳过添加任务`); + continue; + } + + // 检查最后心跳时间 + const lastHeartbeat = device.lastHeartbeat || 0; + const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); + + if (!isOnline) { + const offlineMinutes = lastHeartbeat ? Math.round((now - lastHeartbeat) / (60 * 1000)) : '未知'; + console.log(`[自动沟通] 设备 ${userData.sn_code} 离线(最后心跳: ${offlineMinutes}分钟前),跳过添加任务`); + continue; + } + // 检查设备调度策略 const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'chat'); if (!canExecute.allowed) { diff --git a/api/middleware/schedule/taskQueue.js b/api/middleware/schedule/taskQueue.js index b821574..13ab9ee 100644 --- a/api/middleware/schedule/taskQueue.js +++ b/api/middleware/schedule/taskQueue.js @@ -1069,7 +1069,7 @@ class TaskQueue { runningCount: 0 }; - // 获取当前执行的任务 + // 获取当前执行的任务(优先从内存状态获取,如果没有则从数据库查询) let currentTask = null; if (status.currentTask) { const taskData = status.currentTask; @@ -1082,9 +1082,36 @@ class TaskQueue { currentStep: taskData.currentStep || taskData.current_step || '', startTime: taskData.startTime || taskData.start_time || taskData.created_time }; + } else { + // 如果内存中没有,从数据库查询当前运行的任务 + try { + const taskStatusModel = db.getModel('task_status'); + const runningTask = await taskStatusModel.findOne({ + where: { + sn_code: sn_code, + status: 'running' + }, + order: [['id', 'DESC']] + }); + + if (runningTask) { + const taskData = runningTask.toJSON(); + 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 + }; + } + } catch (error) { + console.error(`[任务队列] 查询当前任务失败:`, error); + } } - // 获取待执行任务列表(最多10个) + // 获取待执行任务列表(优先从内存队列获取,如果没有则从数据库查询) const pendingTasks = []; if (queue && queue.size() > 0) { const queueArray = queue.toArray(); @@ -1099,6 +1126,36 @@ class TaskQueue { priority: taskData.priority || 0 }); } + } else { + // 如果内存队列为空,从数据库查询待执行任务 + try { + const taskStatusModel = db.getModel('task_status'); + const dbPendingTasks = await taskStatusModel.findAll({ + where: { + sn_code: sn_code, + status: 'pending' + }, + order: [ + ['priority', 'DESC'], + ['id', 'ASC'] + ], + limit: 10 + }); + + for (const taskRecord of dbPendingTasks) { + const taskData = taskRecord.toJSON(); + 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 + }); + } + } catch (error) { + console.error(`[任务队列] 查询待执行任务失败:`, error); + } } // 计算下次任务执行时间(队列中第一个任务的计划时间) @@ -1156,6 +1213,7 @@ class TaskQueue { }); await mqttClient.publish(topic, message); + console.log(`[任务队列] 已发送任务状态摘要到 ${sn_code}: 当前任务=${summary.currentTask ? '有' : '无'}, 待执行=${summary.pendingCount}个`); } catch (error) { // 通知失败不影响任务执行,只记录日志 console.warn(`[任务队列] 发送任务状态摘要失败:`, error.message);