From d14f89e008c986cb1f10fad0377e0365e8053e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Tue, 30 Dec 2025 14:51:33 +0800 Subject: [PATCH] 1 --- .claude/settings.local.json | 4 +- api/middleware/job/jobManager.js | 2 +- api/middleware/job/job_filter_service.js | 2 +- api/middleware/schedule/index.js | 2 +- api/middleware/schedule/scheduledJobs.js | 686 ++++++------------- api/middleware/schedule/scheduledJobs_new.js | 570 --------------- api/services/index.js | 4 +- api/services/pla_account_service.js | 2 +- 8 files changed, 236 insertions(+), 1036 deletions(-) delete mode 100644 api/middleware/schedule/scheduledJobs_new.js diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 1a374c0..0e00a2d 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,9 @@ "Bash(mkdir:*)", "Bash(findstr:*)", "Bash(cat:*)", - "Bash(npm run restart:*)" + "Bash(npm run restart:*)", + "Bash(del scheduledJobs.js)", + "Bash(ls:*)" ], "deny": [], "ask": [] diff --git a/api/middleware/job/jobManager.js b/api/middleware/job/jobManager.js index db90f9f..218de29 100644 --- a/api/middleware/job/jobManager.js +++ b/api/middleware/job/jobManager.js @@ -1,6 +1,6 @@ // const aiService = require('./aiService'); // 二期规划:AI 服务暂时禁用 const jobFilterService = require('./job_filter_service'); // 使用文本匹配过滤服务 -const locationService = require('../../services/locationService'); // 位置服务 +const locationService = require('../../services/location_service'); // 位置服务 const logs = require('../logProxy'); const db = require('../dbProxy'); const { v4: uuidv4 } = require('uuid'); diff --git a/api/middleware/job/job_filter_service.js b/api/middleware/job/job_filter_service.js index ede0bd3..29e0743 100644 --- a/api/middleware/job/job_filter_service.js +++ b/api/middleware/job/job_filter_service.js @@ -5,7 +5,7 @@ */ const db = require('../dbProxy.js'); -const locationService = require('../../services/locationService'); +const locationService = require('../../services/location_service'); class JobFilterService { constructor() { diff --git a/api/middleware/schedule/index.js b/api/middleware/schedule/index.js index 99eaae5..367a00c 100644 --- a/api/middleware/schedule/index.js +++ b/api/middleware/schedule/index.js @@ -82,7 +82,7 @@ class ScheduleManager { await deviceManager.init(); // 初始化任务队列 - await TaskQueue.init?.(); + await TaskQueue.init(); } /** diff --git a/api/middleware/schedule/scheduledJobs.js b/api/middleware/schedule/scheduledJobs.js index de64fc9..51b38a9 100644 --- a/api/middleware/schedule/scheduledJobs.js +++ b/api/middleware/schedule/scheduledJobs.js @@ -4,56 +4,16 @@ const config = require('./config.js'); const deviceManager = require('./deviceManager.js'); const command = require('./command.js'); const db = require('../dbProxy'); -const authorizationService = require('../../services/authorization_service.js'); + +// 引入新的任务模块 +const tasks = require('./tasks'); +const { autoSearchTask, autoDeliverTask, autoChatTask, autoActiveTask } = tasks; const Framework = require("../../../framework/node-core-framework.js"); + /** - * 检查当前时间是否在指定的时间范围内 - * @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} - * @returns {Object} {allowed: boolean, reason: string} - */ -function checkTimeRange(timeRange) { - if (!timeRange || !timeRange.start_time || !timeRange.end_time) { - return { allowed: true, reason: '未配置时间范围' }; - } - - const now = new Date(); - const currentHour = now.getHours(); - const currentMinute = now.getMinutes(); - const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数 - - // 解析开始时间和结束时间 - const [startHour, startMinute] = timeRange.start_time.split(':').map(Number); - const [endHour, endMinute] = timeRange.end_time.split(':').map(Number); - const startTime = startHour * 60 + startMinute; - const endTime = endHour * 60 + endMinute; - - // 检查是否仅工作日(使用宽松比较,兼容字符串和数字) - if (timeRange.workdays_only == 1) { // 使用 == 而不是 === - const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六 - if (dayOfWeek === 0 || dayOfWeek === 6) { - return { allowed: false, reason: '当前是周末,不在允许的时间范围内' }; - } - } - - // 检查当前时间是否在时间范围内 - if (startTime <= endTime) { - // 正常情况:09:00 - 18:00 - if (currentTime < startTime || currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } else { - // 跨天情况:22:00 - 06:00 - if (currentTime < startTime && currentTime >= endTime) { - return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` }; - } - } - - return { allowed: true, reason: '在允许的时间范围内' }; -} -/** - * 定时任务管理器(简化版) - * 管理所有定时任务的创建和销毁 + * 定时任务管理器(重构版) + * 使用独立的任务模块,职责更清晰,易于维护和扩展 */ class ScheduledJobs { constructor(components, taskHandlers) { @@ -66,11 +26,16 @@ class ScheduledJobs { * 启动所有定时任务 */ start() { + console.log('[定时任务] 开始启动所有定时任务...'); + + // ==================== 系统维护任务 ==================== + // 每天凌晨重置统计数据 const resetJob = node_schedule.scheduleJob(config.schedules.dailyReset, () => { this.resetDailyStats(); }); this.jobs.push(resetJob); + console.log('[定时任务] ✓ 已启动每日统计重置任务'); // 启动心跳检查定时任务(每分钟检查一次) const monitoringJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { @@ -78,8 +43,8 @@ class ScheduledJobs { console.error('[定时任务] 检查心跳状态失败:', error); }); }); - this.jobs.push(monitoringJob); + console.log('[定时任务] ✓ 已启动心跳检查任务'); // 启动离线设备任务清理定时任务(每分钟检查一次) const cleanupOfflineTasksJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { @@ -87,9 +52,8 @@ class ScheduledJobs { console.error('[定时任务] 清理离线设备任务失败:', error); }); }); - this.jobs.push(cleanupOfflineTasksJob); - console.log('[定时任务] 已启动离线设备任务清理任务'); + console.log('[定时任务] ✓ 已启动离线设备任务清理任务'); // 启动任务超时检查定时任务(每分钟检查一次) const timeoutCheckJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { @@ -97,9 +61,8 @@ class ScheduledJobs { console.error('[定时任务] 检查任务超时失败:', error); }); }); - this.jobs.push(timeoutCheckJob); - console.log('[定时任务] 已启动任务超时检查任务'); + console.log('[定时任务] ✓ 已启动任务超时检查任务'); // 启动任务状态摘要同步定时任务(每10秒发送一次) const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => { @@ -107,36 +70,212 @@ class ScheduledJobs { console.error('[定时任务] 同步任务状态摘要失败:', error); }); }); - this.jobs.push(taskSummaryJob); - console.log('[定时任务] 已启动任务状态摘要同步任务'); + console.log('[定时任务] ✓ 已启动任务状态摘要同步任务'); + // ==================== 业务任务(使用新的任务模块) ==================== - // 执行自动投递任务 + // 1. 自动搜索任务 - 每60分钟执行一次 + const autoSearchJob = node_schedule.scheduleJob(config.schedules.autoSearch || '0 0 */1 * * *', () => { + this.runAutoSearchTask(); + }); + this.jobs.push(autoSearchJob); + console.log('[定时任务] ✓ 已启动自动搜索任务 (每60分钟)'); + + // 2. 自动投递任务 - 每1分钟检查一次 const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => { - this.recommendedSearchJobListTask(); + this.runAutoDeliverTask(); }); - - // 立即执行一次自动投递任务 - this.recommendedSearchJobListTask(); - this.jobs.push(autoDeliverJob); - console.log('[定时任务] 已启动自动投递任务'); + console.log('[定时任务] ✓ 已启动自动投递任务 (每1分钟)'); - // 执行自动沟通任务 + // 3. 自动沟通任务 - 每15分钟执行一次 const autoChatJob = node_schedule.scheduleJob(config.schedules.autoChat || '0 */15 * * * *', () => { - this.autoChatTask(); + this.runAutoChatTask(); }); - - // 立即执行一次自动沟通任务 - this.autoChatTask(); - this.jobs.push(autoChatJob); - console.log('[定时任务] 已启动自动沟通任务'); + console.log('[定时任务] ✓ 已启动自动沟通任务 (每15分钟)'); + // 4. 自动活跃任务 - 每2小时执行一次 + const autoActiveJob = node_schedule.scheduleJob(config.schedules.autoActive || '0 0 */2 * * *', () => { + this.runAutoActiveTask(); + }); + this.jobs.push(autoActiveJob); + console.log('[定时任务] ✓ 已启动自动活跃任务 (每2小时)'); + + // 立即执行一次业务任务(可选) + setTimeout(() => { + console.log('[定时任务] 立即执行一次初始化任务...'); + this.runAutoDeliverTask(); + this.runAutoChatTask(); + }, 3000); // 延迟3秒,等待系统初始化完成 + + console.log('[定时任务] 所有定时任务启动完成!'); } + // ==================== 业务任务执行方法(使用新的任务模块) ==================== + /** + * 运行自动搜索任务 + * 为所有启用自动搜索的账号添加搜索任务 + */ + async runAutoSearchTask() { + try { + const accounts = await this.getEnabledAccounts('auto_search'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动搜索调度] 找到 ${accounts.length} 个启用自动搜索的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoSearchTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动搜索调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动搜索调度] 执行失败:', error); + } + } + + /** + * 运行自动投递任务 + * 为所有启用自动投递的账号添加投递任务 + */ + async runAutoDeliverTask() { + try { + const accounts = await this.getEnabledAccounts('auto_deliver'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动投递调度] 找到 ${accounts.length} 个启用自动投递的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoDeliverTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动投递调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动投递调度] 执行失败:', error); + } + } + + /** + * 运行自动沟通任务 + * 为所有启用自动沟通的账号添加沟通任务 + */ + async runAutoChatTask() { + try { + const accounts = await this.getEnabledAccounts('auto_chat'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动沟通调度] 找到 ${accounts.length} 个启用自动沟通的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoChatTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动沟通调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动沟通调度] 执行失败:', error); + } + } + + /** + * 运行自动活跃任务 + * 为所有启用自动活跃的账号添加活跃任务 + */ + async runAutoActiveTask() { + try { + const accounts = await this.getEnabledAccounts('auto_active'); + + if (accounts.length === 0) { + return; + } + + console.log(`[自动活跃调度] 找到 ${accounts.length} 个启用自动活跃的账号`); + + let successCount = 0; + let failedCount = 0; + + for (const account of accounts) { + const result = await autoActiveTask.addToQueue(account.sn_code, this.taskQueue); + if (result.success) { + successCount++; + } else { + failedCount++; + } + } + + if (successCount > 0 || failedCount > 0) { + console.log(`[自动活跃调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); + } + } catch (error) { + console.error('[自动活跃调度] 执行失败:', error); + } + } + + /** + * 获取启用指定功能的账号列表 + * @param {string} featureType - 功能类型: auto_search, auto_deliver, auto_chat, auto_active + */ + async getEnabledAccounts(featureType) { + try { + const { pla_account } = db.models; + + const accounts = await pla_account.findAll({ + where: { + is_delete: 0, + is_enabled: 1, + [featureType]: 1 + }, + attributes: ['sn_code', 'name', 'keyword', 'platform_type'] + }); + + return accounts.map(acc => acc.toJSON()); + } catch (error) { + console.error(`[获取账号列表] 失败 (${featureType}):`, error); + return []; + } + } + + // ==================== 系统维护方法(保留原有逻辑) ==================== /** * 重置每日统计 @@ -174,7 +313,7 @@ class ScheduledJobs { async cleanupOfflineDeviceTasks() { try { // 离线阈值:10分钟 - const offlineThreshold = 10 * 60 * 1000; // 10分钟 + const offlineThreshold = 10 * 60 * 1000; const now = Date.now(); const thresholdTime = now - offlineThreshold; @@ -201,14 +340,12 @@ class ScheduledJobs { const device = deviceManager.devices.get(sn_code); if (!device) { - // 设备从未发送过心跳,视为离线 offlineSnCodes.push(sn_code); offlineDevicesInfo.push({ sn_code: sn_code, lastHeartbeatTime: null }); } else { - // 检查最后心跳时间 const lastHeartbeat = device.lastHeartbeat || 0; if (lastHeartbeat < thresholdTime || !device.isOnline) { offlineSnCodes.push(sn_code); @@ -224,30 +361,15 @@ class ScheduledJobs { return; } - console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备: ${offlineSnCodes.join(', ')}`); + console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备`); let totalCancelled = 0; - - // 为每个离线设备取消任务 const task_status = db.getModel('task_status'); + for (const sn_code of offlineSnCodes) { try { - // 查询该设备的所有pending/running任务 - const pendingTasks = await task_status.findAll({ - where: { - sn_code: sn_code, - status: ['pending', 'running'] - }, - attributes: ['id'] - }); - - if (pendingTasks.length === 0) { - continue; - } - const deviceInfo = offlineDevicesInfo.find(d => d.sn_code === sn_code); - // 更新任务状态为cancelled const updateResult = await task_status.update( { status: 'cancelled', @@ -268,12 +390,13 @@ class ScheduledJobs { const cancelledCount = Array.isArray(updateResult) ? updateResult[0] : updateResult; totalCancelled += cancelledCount; - // 从内存队列中移除任务 if (this.taskQueue && typeof this.taskQueue.cancelDeviceTasks === 'function') { await this.taskQueue.cancelDeviceTasks(sn_code); } - console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`); + if (cancelledCount > 0) { + console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`); + } } catch (error) { console.error(`[清理离线任务] 取消设备 ${sn_code} 的任务失败:`, error); } @@ -289,13 +412,11 @@ class ScheduledJobs { /** * 同步任务状态摘要到客户端 - * 定期向所有在线设备发送任务状态摘要(当前任务、待执行任务、下次执行时间等) */ async syncTaskStatusSummary() { try { const { pla_account } = await Framework.getModels(); - // 获取所有启用的账号 const accounts = await pla_account.findAll({ where: { is_delete: 0, @@ -308,32 +429,24 @@ class ScheduledJobs { return; } - // 离线阈值:3分钟 - const offlineThreshold = 3 * 60 * 1000; // 3分钟 + const offlineThreshold = 3 * 60 * 1000; const now = Date.now(); - // 为每个在线设备发送任务状态摘要 for (const account of accounts) { const sn_code = account.sn_code; - - // 检查设备是否在线 const device = deviceManager.devices.get(sn_code); if (!device) { - // 设备从未发送过心跳,视为离线,跳过 continue; } - // 检查最后心跳时间 const lastHeartbeat = device.lastHeartbeat || 0; const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); if (!isOnline) { - // 设备离线,跳过 continue; } - // 设备在线,推送设备工作状态 try { const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); const summary = await this.taskQueue.getTaskStatusSummary(sn_code); @@ -351,14 +464,12 @@ class ScheduledJobs { /** * 检查任务超时并强制标记为失败 - * 检测长时间运行的任务(可能是卡住的),强制标记为失败,释放资源 */ async checkTaskTimeouts() { try { const Sequelize = require('sequelize'); const { task_status, op } = db.models; - // 查询所有运行中的任务 const runningTasks = await task_status.findAll({ where: { status: 'running' @@ -381,13 +492,10 @@ class ScheduledJobs { continue; } - // 获取任务类型的超时时间(默认10分钟) const taskTimeout = config.getTaskTimeout(taskData.taskType) || 10 * 60 * 1000; - // 允许额外20%的缓冲时间 const maxAllowedTime = taskTimeout * 1.2; const elapsedTime = now.getTime() - startTime.getTime(); - // 如果任务运行时间超过最大允许时间,标记为超时失败 if (elapsedTime > maxAllowedTime) { try { await task_status.update( @@ -409,42 +517,33 @@ class ScheduledJobs { ); timeoutCount++; - console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长,已强制标记为失败`, { - task_id: taskData.id, - sn_code: taskData.sn_code, - taskType: taskData.taskType, - elapsedTime: Math.round(elapsedTime / 1000) + '秒', - maxAllowedTime: Math.round(maxAllowedTime / 1000) + '秒' - }); + console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长,已强制标记为失败`); - // 如果任务队列中有这个任务,也需要从内存中清理 if (this.taskQueue && typeof this.taskQueue.deviceStatus !== 'undefined') { const deviceStatus = this.taskQueue.deviceStatus.get(taskData.sn_code); if (deviceStatus && deviceStatus.currentTask && deviceStatus.currentTask.id === taskData.id) { - // 重置设备状态,允许继续执行下一个任务 deviceStatus.isRunning = false; deviceStatus.currentTask = null; deviceStatus.runningCount = Math.max(0, deviceStatus.runningCount - 1); this.taskQueue.globalRunningCount = Math.max(0, this.taskQueue.globalRunningCount - 1); - console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态,可以继续执行下一个任务`); + console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态`); - // 尝试继续处理该设备的队列 setTimeout(() => { this.taskQueue.processQueue(taskData.sn_code).catch(error => { - console.error(`[任务超时检查] 继续处理队列失败 (设备: ${taskData.sn_code}):`, error); + console.error(`[任务超时检查] 继续处理队列失败:`, error); }); }, 100); } } } catch (error) { - console.error(`[任务超时检查] 更新超时任务状态失败 (任务ID: ${taskData.id}):`, error); + console.error(`[任务超时检查] 更新超时任务状态失败:`, error); } } } if (timeoutCount > 0) { - console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务,已强制标记为失败`); + console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务`); } } catch (error) { console.error('[任务超时检查] 执行失败:', error); @@ -452,349 +551,20 @@ class ScheduledJobs { } /** - * 推荐职位列表任务 + * 停止所有定时任务 */ - async recommendedSearchJobListTask() { - const now = new Date(); - console.log(`[自动投递] ${now.toLocaleString()} 开始执行自动投递任务`); + stop() { + console.log('[定时任务] 停止所有定时任务...'); - - - try { - // 移除 device_status 依赖,改为直接从 pla_account 查询启用且开启自动投递的账号 - const models = db.models; - const { pla_account, op } = models; - - // 直接从 pla_account 查询启用且开启自动投递的账号 - // 注意:不再检查在线状态,因为 device_status 已移除 - const pla_users = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1, // 只获取启用的账号 - auto_deliver: 1 - } - }); - - - - if (!pla_users || pla_users.length === 0) { - console.log('[自动投递] 没有启用且开启自动投递的账号'); - return; + for (const job of this.jobs) { + if (job) { + job.cancel(); } - - console.log(`[自动投递] 找到 ${pla_users.length} 个可用账号`); - - // 获取 task_status 模型用于查询上次投递时间 - const { task_status } = models; - - // 为每个设备添加自动投递任务到队列 - 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); - - - // 检查用户授权天数 是否够 - const authorization = await authorizationService.checkAuthorization(userData.sn_code); - if (!authorization.is_authorized) { - console.log(`[自动投递] 设备 ${userData.sn_code} 授权天数不足,跳过添加任务`); - continue; - } - - - 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) { - console.log(`[自动投递] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`); - continue; - } - - // 获取投递配置,如果不存在则使用默认值 - let deliver_config = userData.deliver_config; - if (typeof deliver_config === 'string') { - try { - deliver_config = JSON.parse(deliver_config); - } catch (e) { - deliver_config = {}; - } - } - deliver_config = deliver_config || { - deliver_interval: 30, - min_salary: 0, - max_salary: 0, - page_count: 3, - max_deliver: 10, - filter_keywords: [], - exclude_keywords: [] - }; - - // 检查投递时间范围 - if (deliver_config.time_range) { - const timeCheck = checkTimeRange(deliver_config.time_range); - if (!timeCheck.allowed) { - console.log(`[自动投递] 设备 ${userData.sn_code} ${timeCheck.reason}`); - continue; - } - } - - // 检查投递间隔时间 - const deliver_interval = deliver_config.deliver_interval || 30; // 默认30分钟 - const interval_ms = deliver_interval * 60 * 1000; // 转换为毫秒 - - // 查询该账号最近一次成功完成的自动投递任务 - const lastDeliverTask = await task_status.findOne({ - where: { - sn_code: userData.sn_code, - taskType: 'auto_deliver', - status: 'completed' - }, - order: [['endTime', 'DESC']], - attributes: ['endTime'] - }); - - // 如果存在上次投递记录,检查是否已经过了间隔时间 - if (lastDeliverTask && lastDeliverTask.endTime) { - const lastDeliverTime = new Date(lastDeliverTask.endTime); - - const elapsedTime = new Date().getTime() - lastDeliverTime.getTime(); - - if (elapsedTime < interval_ms) { - const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); - const elapsedMinutes = Math.round(elapsedTime / (60 * 1000)); - const message = `距离上次投递仅 ${elapsedMinutes} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${deliver_interval} 分钟)`; - console.log(`[自动投递] 设备 ${userData.sn_code} ${message}`); - - // 推送等待状态到客户端 - try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); - - // 获取当前任务状态摘要 - const taskStatusSummary = this.taskQueue ? this.taskQueue.getTaskStatusSummary(userData.sn_code) : { - sn_code: userData.sn_code, - pendingCount: 0, - totalPendingCount: 0, - pendingTasks: [] - }; - - // 添加等待消息到工作状态 - await deviceWorkStatusNotifier.sendDeviceWorkStatus(userData.sn_code, taskStatusSummary, { - waitingMessage: { - type: 'deliver_interval', - message: message, - remainingMinutes: remainingMinutes, - nextDeliverTime: new Date(lastDeliverTime.getTime() + interval_ms).toISOString() - } - }); - } catch (pushError) { - console.warn(`[自动投递] 推送等待消息失败:`, pushError.message); - } - - continue; - } - } - - // 添加自动投递任务到队列 - await this.taskQueue.addTask(userData.sn_code, { - taskType: 'auto_deliver', - taskName: `自动投递 - ${userData.keyword || ''}`, - taskParams: { - keyword: userData.keyword || '', - platform: userData.platform_type || 'boss', - pageCount: deliver_config.page_count || 3, - maxCount: deliver_config.max_deliver || 10, - filterRules: { - minSalary: deliver_config.min_salary || 0, - maxSalary: deliver_config.max_salary || 0, - keywords: deliver_config.filter_keywords || [], - excludeKeywords: deliver_config.exclude_keywords || [] - } - }, - priority: config.getTaskPriority('auto_deliver') || 6 - }); - - console.log(`[自动投递] 已为设备 ${userData.sn_code} 添加自动投递任务,关键词: ${userData.keyword || '默认'},投递间隔: ${deliver_interval} 分钟`); - } - - console.log('[自动投递] 任务添加完成'); - - } catch (error) { - console.error('[自动投递] 执行失败:', error); } + + this.jobs = []; + console.log('[定时任务] 所有定时任务已停止'); } - - - /** - * 搜索职位列表任务 - */ - async searchJobListTask() { - const now = new Date(); - console.log(`[搜索职位列表] ${now.toLocaleString()} 开始执行搜索职位列表任务`); - - try { - - const models = db.models; - const { pla_account, op } = models; - - } catch (error) { - console.error('[搜索职位列表] 执行失败:', error); - } - } - - - /** - * 自动沟通任务 - */ - async autoChatTask() { - const now = new Date(); - console.log(`[自动沟通] ${now.toLocaleString()} 开始执行自动沟通任务`); - - - - try { - // 移除 device_status 依赖,改为直接从 pla_account 查询启用且开启自动沟通的账号 - const models = db.models; - const { pla_account, op } = models; - - // 直接从 pla_account 查询启用且开启自动沟通的账号 - // 注意:不再检查在线状态,因为 device_status 已移除 - const pla_users = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1, // 只获取启用的账号 - auto_chat: 1 - } - }); - - if (!pla_users || pla_users.length === 0) { - console.log('[自动沟通] 没有启用且开启自动沟通的账号'); - return; - } - - console.log(`[自动沟通] 找到 ${pla_users.length} 个可用账号`); - - // 获取 task_status 模型用于查询上次沟通时间 - const { task_status } = models; - - // 为每个设备添加自动沟通任务到队列 - 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) { - console.log(`[自动沟通] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`); - continue; - } - - // 获取沟通策略配置 - let chatStrategy = {}; - if (userData.chat_strategy) { - chatStrategy = typeof userData.chat_strategy === 'string' - ? JSON.parse(userData.chat_strategy) - : userData.chat_strategy; - } - - // 检查沟通时间范围 - if (chatStrategy.time_range) { - const timeCheck = checkTimeRange(chatStrategy.time_range); - if (!timeCheck.allowed) { - console.log(`[自动沟通] 设备 ${userData.sn_code} ${timeCheck.reason}`); - continue; - } - } - - // 检查沟通间隔时间 - const chat_interval = chatStrategy.chat_interval || 30; // 默认30分钟 - const interval_ms = chat_interval * 60 * 1000; // 转换为毫秒 - - // 查询该账号最近一次成功完成的自动沟通任务 - const lastChatTask = await task_status.findOne({ - where: { - sn_code: userData.sn_code, - taskType: 'auto_chat', - status: 'completed' - }, - order: [['endTime', 'DESC']], - attributes: ['endTime'] - }); - - // 如果存在上次沟通记录,检查是否已经过了间隔时间 - if (lastChatTask && lastChatTask.endTime) { - const lastChatTime = new Date(lastChatTask.endTime); - const elapsedTime = now.getTime() - lastChatTime.getTime(); - - if (elapsedTime < interval_ms) { - const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000)); - console.log(`[自动沟通] 设备 ${userData.sn_code} 距离上次沟通仅 ${Math.round(elapsedTime / (60 * 1000))} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${chat_interval} 分钟)`); - continue; - } - } - - // 添加自动沟通任务到队列 - await this.taskQueue.addTask(userData.sn_code, { - taskType: 'auto_chat', - taskName: `自动沟通 - ${userData.name || '默认'}`, - taskParams: { - platform: userData.platform_type || 'boss' - }, - priority: config.getTaskPriority('auto_chat') || 6 - }); - - console.log(`[自动沟通] 已为设备 ${userData.sn_code} 添加自动沟通任务,沟通间隔: ${chat_interval} 分钟`); - } - - console.log('[自动沟通] 任务添加完成'); - - } catch (error) { - console.error('[自动沟通] 执行失败:', error); - } - } - - } module.exports = ScheduledJobs; - diff --git a/api/middleware/schedule/scheduledJobs_new.js b/api/middleware/schedule/scheduledJobs_new.js deleted file mode 100644 index 51b38a9..0000000 --- a/api/middleware/schedule/scheduledJobs_new.js +++ /dev/null @@ -1,570 +0,0 @@ -const node_schedule = require("node-schedule"); -const dayjs = require('dayjs'); -const config = require('./config.js'); -const deviceManager = require('./deviceManager.js'); -const command = require('./command.js'); -const db = require('../dbProxy'); - -// 引入新的任务模块 -const tasks = require('./tasks'); -const { autoSearchTask, autoDeliverTask, autoChatTask, autoActiveTask } = tasks; - -const Framework = require("../../../framework/node-core-framework.js"); - -/** - * 定时任务管理器(重构版) - * 使用独立的任务模块,职责更清晰,易于维护和扩展 - */ -class ScheduledJobs { - constructor(components, taskHandlers) { - this.taskQueue = components.taskQueue; - this.taskHandlers = taskHandlers; - this.jobs = []; - } - - /** - * 启动所有定时任务 - */ - start() { - console.log('[定时任务] 开始启动所有定时任务...'); - - // ==================== 系统维护任务 ==================== - - // 每天凌晨重置统计数据 - const resetJob = node_schedule.scheduleJob(config.schedules.dailyReset, () => { - this.resetDailyStats(); - }); - this.jobs.push(resetJob); - console.log('[定时任务] ✓ 已启动每日统计重置任务'); - - // 启动心跳检查定时任务(每分钟检查一次) - const monitoringJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await deviceManager.checkHeartbeatStatus().catch(error => { - console.error('[定时任务] 检查心跳状态失败:', error); - }); - }); - this.jobs.push(monitoringJob); - console.log('[定时任务] ✓ 已启动心跳检查任务'); - - // 启动离线设备任务清理定时任务(每分钟检查一次) - const cleanupOfflineTasksJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await this.cleanupOfflineDeviceTasks().catch(error => { - console.error('[定时任务] 清理离线设备任务失败:', error); - }); - }); - this.jobs.push(cleanupOfflineTasksJob); - console.log('[定时任务] ✓ 已启动离线设备任务清理任务'); - - // 启动任务超时检查定时任务(每分钟检查一次) - const timeoutCheckJob = node_schedule.scheduleJob(config.schedules.monitoringInterval, async () => { - await this.checkTaskTimeouts().catch(error => { - console.error('[定时任务] 检查任务超时失败:', error); - }); - }); - this.jobs.push(timeoutCheckJob); - console.log('[定时任务] ✓ 已启动任务超时检查任务'); - - // 启动任务状态摘要同步定时任务(每10秒发送一次) - const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => { - await this.syncTaskStatusSummary().catch(error => { - console.error('[定时任务] 同步任务状态摘要失败:', error); - }); - }); - this.jobs.push(taskSummaryJob); - console.log('[定时任务] ✓ 已启动任务状态摘要同步任务'); - - // ==================== 业务任务(使用新的任务模块) ==================== - - // 1. 自动搜索任务 - 每60分钟执行一次 - const autoSearchJob = node_schedule.scheduleJob(config.schedules.autoSearch || '0 0 */1 * * *', () => { - this.runAutoSearchTask(); - }); - this.jobs.push(autoSearchJob); - console.log('[定时任务] ✓ 已启动自动搜索任务 (每60分钟)'); - - // 2. 自动投递任务 - 每1分钟检查一次 - const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => { - this.runAutoDeliverTask(); - }); - this.jobs.push(autoDeliverJob); - console.log('[定时任务] ✓ 已启动自动投递任务 (每1分钟)'); - - // 3. 自动沟通任务 - 每15分钟执行一次 - const autoChatJob = node_schedule.scheduleJob(config.schedules.autoChat || '0 */15 * * * *', () => { - this.runAutoChatTask(); - }); - this.jobs.push(autoChatJob); - console.log('[定时任务] ✓ 已启动自动沟通任务 (每15分钟)'); - - // 4. 自动活跃任务 - 每2小时执行一次 - const autoActiveJob = node_schedule.scheduleJob(config.schedules.autoActive || '0 0 */2 * * *', () => { - this.runAutoActiveTask(); - }); - this.jobs.push(autoActiveJob); - console.log('[定时任务] ✓ 已启动自动活跃任务 (每2小时)'); - - // 立即执行一次业务任务(可选) - setTimeout(() => { - console.log('[定时任务] 立即执行一次初始化任务...'); - this.runAutoDeliverTask(); - this.runAutoChatTask(); - }, 3000); // 延迟3秒,等待系统初始化完成 - - console.log('[定时任务] 所有定时任务启动完成!'); - } - - // ==================== 业务任务执行方法(使用新的任务模块) ==================== - - /** - * 运行自动搜索任务 - * 为所有启用自动搜索的账号添加搜索任务 - */ - async runAutoSearchTask() { - try { - const accounts = await this.getEnabledAccounts('auto_search'); - - if (accounts.length === 0) { - return; - } - - console.log(`[自动搜索调度] 找到 ${accounts.length} 个启用自动搜索的账号`); - - let successCount = 0; - let failedCount = 0; - - for (const account of accounts) { - const result = await autoSearchTask.addToQueue(account.sn_code, this.taskQueue); - if (result.success) { - successCount++; - } else { - failedCount++; - } - } - - if (successCount > 0 || failedCount > 0) { - console.log(`[自动搜索调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); - } - } catch (error) { - console.error('[自动搜索调度] 执行失败:', error); - } - } - - /** - * 运行自动投递任务 - * 为所有启用自动投递的账号添加投递任务 - */ - async runAutoDeliverTask() { - try { - const accounts = await this.getEnabledAccounts('auto_deliver'); - - if (accounts.length === 0) { - return; - } - - console.log(`[自动投递调度] 找到 ${accounts.length} 个启用自动投递的账号`); - - let successCount = 0; - let failedCount = 0; - - for (const account of accounts) { - const result = await autoDeliverTask.addToQueue(account.sn_code, this.taskQueue); - if (result.success) { - successCount++; - } else { - failedCount++; - } - } - - if (successCount > 0 || failedCount > 0) { - console.log(`[自动投递调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); - } - } catch (error) { - console.error('[自动投递调度] 执行失败:', error); - } - } - - /** - * 运行自动沟通任务 - * 为所有启用自动沟通的账号添加沟通任务 - */ - async runAutoChatTask() { - try { - const accounts = await this.getEnabledAccounts('auto_chat'); - - if (accounts.length === 0) { - return; - } - - console.log(`[自动沟通调度] 找到 ${accounts.length} 个启用自动沟通的账号`); - - let successCount = 0; - let failedCount = 0; - - for (const account of accounts) { - const result = await autoChatTask.addToQueue(account.sn_code, this.taskQueue); - if (result.success) { - successCount++; - } else { - failedCount++; - } - } - - if (successCount > 0 || failedCount > 0) { - console.log(`[自动沟通调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); - } - } catch (error) { - console.error('[自动沟通调度] 执行失败:', error); - } - } - - /** - * 运行自动活跃任务 - * 为所有启用自动活跃的账号添加活跃任务 - */ - async runAutoActiveTask() { - try { - const accounts = await this.getEnabledAccounts('auto_active'); - - if (accounts.length === 0) { - return; - } - - console.log(`[自动活跃调度] 找到 ${accounts.length} 个启用自动活跃的账号`); - - let successCount = 0; - let failedCount = 0; - - for (const account of accounts) { - const result = await autoActiveTask.addToQueue(account.sn_code, this.taskQueue); - if (result.success) { - successCount++; - } else { - failedCount++; - } - } - - if (successCount > 0 || failedCount > 0) { - console.log(`[自动活跃调度] 完成: 成功 ${successCount} 个, 失败/跳过 ${failedCount} 个`); - } - } catch (error) { - console.error('[自动活跃调度] 执行失败:', error); - } - } - - /** - * 获取启用指定功能的账号列表 - * @param {string} featureType - 功能类型: auto_search, auto_deliver, auto_chat, auto_active - */ - async getEnabledAccounts(featureType) { - try { - const { pla_account } = db.models; - - const accounts = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1, - [featureType]: 1 - }, - attributes: ['sn_code', 'name', 'keyword', 'platform_type'] - }); - - return accounts.map(acc => acc.toJSON()); - } catch (error) { - console.error(`[获取账号列表] 失败 (${featureType}):`, error); - return []; - } - } - - // ==================== 系统维护方法(保留原有逻辑) ==================== - - /** - * 重置每日统计 - */ - resetDailyStats() { - console.log('[定时任务] 重置每日统计数据'); - - try { - deviceManager.resetAllDailyCounters(); - console.log('[定时任务] 每日统计重置完成'); - } catch (error) { - console.error('[定时任务] 重置统计失败:', error); - } - } - - /** - * 清理过期数据 - */ - cleanupCaches() { - console.log('[定时任务] 开始清理过期数据'); - - try { - deviceManager.cleanupOfflineDevices(config.monitoring.offlineThreshold); - command.cleanupExpiredCommands(30); - console.log('[定时任务] 数据清理完成'); - } catch (error) { - console.error('[定时任务] 数据清理失败:', error); - } - } - - /** - * 清理离线设备任务 - * 检查离线超过10分钟的设备,取消其所有pending/running状态的任务 - */ - async cleanupOfflineDeviceTasks() { - try { - // 离线阈值:10分钟 - const offlineThreshold = 10 * 60 * 1000; - const now = Date.now(); - const thresholdTime = now - offlineThreshold; - - // 获取所有启用的账号 - const pla_account = db.getModel('pla_account'); - const accounts = await pla_account.findAll({ - where: { - is_delete: 0, - is_enabled: 1 - }, - attributes: ['sn_code'] - }); - - if (!accounts || accounts.length === 0) { - return; - } - - // 通过 deviceManager 检查哪些设备离线超过10分钟 - const offlineSnCodes = []; - const offlineDevicesInfo = []; - - for (const account of accounts) { - const sn_code = account.sn_code; - const device = deviceManager.devices.get(sn_code); - - if (!device) { - offlineSnCodes.push(sn_code); - offlineDevicesInfo.push({ - sn_code: sn_code, - lastHeartbeatTime: null - }); - } else { - const lastHeartbeat = device.lastHeartbeat || 0; - if (lastHeartbeat < thresholdTime || !device.isOnline) { - offlineSnCodes.push(sn_code); - offlineDevicesInfo.push({ - sn_code: sn_code, - lastHeartbeatTime: lastHeartbeat ? new Date(lastHeartbeat) : null - }); - } - } - } - - if (offlineSnCodes.length === 0) { - return; - } - - console.log(`[清理离线任务] 发现 ${offlineSnCodes.length} 个离线超过10分钟的设备`); - - let totalCancelled = 0; - const task_status = db.getModel('task_status'); - - for (const sn_code of offlineSnCodes) { - try { - const deviceInfo = offlineDevicesInfo.find(d => d.sn_code === sn_code); - - const updateResult = await task_status.update( - { - status: 'cancelled', - endTime: new Date(), - result: JSON.stringify({ - reason: '设备离线超过10分钟,任务已自动取消', - offlineTime: deviceInfo?.lastHeartbeatTime - }) - }, - { - where: { - sn_code: sn_code, - status: ['pending', 'running'] - } - } - ); - - const cancelledCount = Array.isArray(updateResult) ? updateResult[0] : updateResult; - totalCancelled += cancelledCount; - - if (this.taskQueue && typeof this.taskQueue.cancelDeviceTasks === 'function') { - await this.taskQueue.cancelDeviceTasks(sn_code); - } - - if (cancelledCount > 0) { - console.log(`[清理离线任务] 设备 ${sn_code} 已取消 ${cancelledCount} 个任务`); - } - } catch (error) { - console.error(`[清理离线任务] 取消设备 ${sn_code} 的任务失败:`, error); - } - } - - if (totalCancelled > 0) { - console.log(`[清理离线任务] 共取消 ${totalCancelled} 个离线设备的任务`); - } - } catch (error) { - console.error('[清理离线任务] 执行失败:', error); - } - } - - /** - * 同步任务状态摘要到客户端 - */ - 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; - } - - const offlineThreshold = 3 * 60 * 1000; - const now = Date.now(); - - for (const account of accounts) { - const sn_code = account.sn_code; - const device = deviceManager.devices.get(sn_code); - - if (!device) { - continue; - } - - const lastHeartbeat = device.lastHeartbeat || 0; - const isOnline = device.isOnline && (now - lastHeartbeat < offlineThreshold); - - if (!isOnline) { - continue; - } - - try { - const deviceWorkStatusNotifier = require('./deviceWorkStatusNotifier'); - const summary = await this.taskQueue.getTaskStatusSummary(sn_code); - await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, summary, { - currentCommand: summary.currentCommand || null - }); - } catch (error) { - console.error(`[设备工作状态同步] 设备 ${sn_code} 同步失败:`, error.message); - } - } - } catch (error) { - console.error('[任务状态同步] 执行失败:', error); - } - } - - /** - * 检查任务超时并强制标记为失败 - */ - async checkTaskTimeouts() { - try { - const Sequelize = require('sequelize'); - const { task_status, op } = db.models; - - const runningTasks = await task_status.findAll({ - where: { - status: 'running' - }, - attributes: ['id', 'sn_code', 'taskType', 'taskName', 'startTime', 'create_time'] - }); - - if (!runningTasks || runningTasks.length === 0) { - return; - } - - const now = new Date(); - let timeoutCount = 0; - - for (const task of runningTasks) { - const taskData = task.toJSON(); - const startTime = taskData.startTime ? new Date(taskData.startTime) : (taskData.create_time ? new Date(taskData.create_time) : null); - - if (!startTime) { - continue; - } - - const taskTimeout = config.getTaskTimeout(taskData.taskType) || 10 * 60 * 1000; - const maxAllowedTime = taskTimeout * 1.2; - const elapsedTime = now.getTime() - startTime.getTime(); - - if (elapsedTime > maxAllowedTime) { - try { - await task_status.update( - { - status: 'failed', - endTime: now, - duration: elapsedTime, - result: JSON.stringify({ - error: `任务执行超时(运行时间: ${Math.round(elapsedTime / 1000)}秒,超时限制: ${Math.round(maxAllowedTime / 1000)}秒)`, - timeout: true, - taskType: taskData.taskType, - startTime: startTime.toISOString() - }), - progress: 0 - }, - { - where: { id: taskData.id } - } - ); - - timeoutCount++; - console.warn(`[任务超时检查] 任务 ${taskData.id} (${taskData.taskName}) 运行时间过长,已强制标记为失败`); - - if (this.taskQueue && typeof this.taskQueue.deviceStatus !== 'undefined') { - const deviceStatus = this.taskQueue.deviceStatus.get(taskData.sn_code); - if (deviceStatus && deviceStatus.currentTask && deviceStatus.currentTask.id === taskData.id) { - deviceStatus.isRunning = false; - deviceStatus.currentTask = null; - deviceStatus.runningCount = Math.max(0, deviceStatus.runningCount - 1); - this.taskQueue.globalRunningCount = Math.max(0, this.taskQueue.globalRunningCount - 1); - - console.log(`[任务超时检查] 已重置设备 ${taskData.sn_code} 的状态`); - - setTimeout(() => { - this.taskQueue.processQueue(taskData.sn_code).catch(error => { - console.error(`[任务超时检查] 继续处理队列失败:`, error); - }); - }, 100); - } - } - } catch (error) { - console.error(`[任务超时检查] 更新超时任务状态失败:`, error); - } - } - } - - if (timeoutCount > 0) { - console.log(`[任务超时检查] 共检测到 ${timeoutCount} 个超时任务`); - } - } catch (error) { - console.error('[任务超时检查] 执行失败:', error); - } - } - - /** - * 停止所有定时任务 - */ - stop() { - console.log('[定时任务] 停止所有定时任务...'); - - for (const job of this.jobs) { - if (job) { - job.cancel(); - } - } - - this.jobs = []; - console.log('[定时任务] 所有定时任务已停止'); - } -} - -module.exports = ScheduledJobs; diff --git a/api/services/index.js b/api/services/index.js index c9f9c62..6113a7c 100644 --- a/api/services/index.js +++ b/api/services/index.js @@ -112,7 +112,5 @@ module.exports = { // 导出各个服务类 AIService, PlaAccountService - // TaskScheduler 已废弃 - // MQTTHandler 文件不存在 - // JobService 已合并到 middleware/job/jobManager.js + }; diff --git a/api/services/pla_account_service.js b/api/services/pla_account_service.js index c40e5fc..5436a82 100644 --- a/api/services/pla_account_service.js +++ b/api/services/pla_account_service.js @@ -5,7 +5,7 @@ const db = require('../middleware/dbProxy'); const scheduleManager = require('../middleware/schedule/index.js'); -const locationService = require('./locationService'); +const locationService = require('./location_service'); const authorizationService = require('./authorization_service'); const { addRemainingDays, addRemainingDaysToAccounts } = require('../utils/account_utils');